@memberjunction/react-test-harness 2.123.1 → 2.125.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.
Files changed (40) hide show
  1. package/dist/lib/component-linter.d.ts.map +1 -1
  2. package/dist/lib/component-linter.js +433 -2
  3. package/dist/lib/component-linter.js.map +1 -1
  4. package/dist/lib/constraint-validators/base-constraint-validator.d.ts +259 -0
  5. package/dist/lib/constraint-validators/base-constraint-validator.d.ts.map +1 -0
  6. package/dist/lib/constraint-validators/base-constraint-validator.js +304 -0
  7. package/dist/lib/constraint-validators/base-constraint-validator.js.map +1 -0
  8. package/dist/lib/constraint-validators/index.d.ts +21 -0
  9. package/dist/lib/constraint-validators/index.d.ts.map +1 -0
  10. package/dist/lib/constraint-validators/index.js +37 -0
  11. package/dist/lib/constraint-validators/index.js.map +1 -0
  12. package/dist/lib/constraint-validators/required-when-validator.d.ts +43 -0
  13. package/dist/lib/constraint-validators/required-when-validator.d.ts.map +1 -0
  14. package/dist/lib/constraint-validators/required-when-validator.js +97 -0
  15. package/dist/lib/constraint-validators/required-when-validator.js.map +1 -0
  16. package/dist/lib/constraint-validators/sql-where-clause-validator.d.ts +116 -0
  17. package/dist/lib/constraint-validators/sql-where-clause-validator.d.ts.map +1 -0
  18. package/dist/lib/constraint-validators/sql-where-clause-validator.js +381 -0
  19. package/dist/lib/constraint-validators/sql-where-clause-validator.js.map +1 -0
  20. package/dist/lib/constraint-validators/subset-of-entity-fields-validator.d.ts +60 -0
  21. package/dist/lib/constraint-validators/subset-of-entity-fields-validator.d.ts.map +1 -0
  22. package/dist/lib/constraint-validators/subset-of-entity-fields-validator.js +198 -0
  23. package/dist/lib/constraint-validators/subset-of-entity-fields-validator.js.map +1 -0
  24. package/dist/lib/constraint-validators/validation-context.d.ts +326 -0
  25. package/dist/lib/constraint-validators/validation-context.d.ts.map +1 -0
  26. package/dist/lib/constraint-validators/validation-context.js +14 -0
  27. package/dist/lib/constraint-validators/validation-context.js.map +1 -0
  28. package/dist/lib/prop-value-extractor.d.ts +147 -0
  29. package/dist/lib/prop-value-extractor.d.ts.map +1 -0
  30. package/dist/lib/prop-value-extractor.js +499 -0
  31. package/dist/lib/prop-value-extractor.js.map +1 -0
  32. package/dist/lib/type-context.d.ts +2 -0
  33. package/dist/lib/type-context.d.ts.map +1 -1
  34. package/dist/lib/type-context.js +22 -9
  35. package/dist/lib/type-context.js.map +1 -1
  36. package/dist/lib/type-inference-engine.d.ts +20 -0
  37. package/dist/lib/type-inference-engine.d.ts.map +1 -1
  38. package/dist/lib/type-inference-engine.js +253 -20
  39. package/dist/lib/type-inference-engine.js.map +1 -1
  40. package/package.json +13 -9
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Subset Of Entity Fields Validator
3
+ *
4
+ * Validates that array elements are valid field names for a specified entity.
5
+ *
6
+ * This validator is essential for catching errors like:
7
+ * ```jsx
8
+ * // ❌ BROKEN - FullName, Status, StartDate don't exist on Members
9
+ * <EntityDataGrid
10
+ * entityName="Members"
11
+ * fields={['FullName', 'Status', 'StartDate']}
12
+ * />
13
+ *
14
+ * // ✅ FIXED - FirstName, LastName, Email exist on Members
15
+ * <EntityDataGrid
16
+ * entityName="Members"
17
+ * fields={['FirstName', 'LastName', 'Email']}
18
+ * />
19
+ * ```
20
+ *
21
+ * Constraint Definition:
22
+ * ```json
23
+ * {
24
+ * "type": "subset-of-entity-fields",
25
+ * "dependsOn": "entityName",
26
+ * "config": {
27
+ * "allowWildcard": false,
28
+ * "caseSensitive": false
29
+ * }
30
+ * }
31
+ * ```
32
+ */
33
+ import { PropertyConstraint, ConstraintViolation } from '@memberjunction/interactive-component-types';
34
+ import { BaseConstraintValidator } from './base-constraint-validator';
35
+ import { ValidationContext } from './validation-context';
36
+ /**
37
+ * Validates that array elements are valid field names for an entity
38
+ *
39
+ * **Depends On**: Entity name (from entityName prop)
40
+ * **Validates**: Array of field name strings
41
+ * **Common Use Cases**:
42
+ * - EntityDataGrid fields prop
43
+ * - DataGrid columns (when using entity binding)
44
+ * - Custom components with entity field arrays
45
+ */
46
+ export declare class SubsetOfEntityFieldsValidator extends BaseConstraintValidator {
47
+ /**
48
+ * Validate that array elements are valid entity field names
49
+ *
50
+ * @param context - Validation context
51
+ * @param constraint - Constraint definition
52
+ * @returns Array of violations (empty if valid)
53
+ */
54
+ validate(context: ValidationContext, constraint: PropertyConstraint): ConstraintViolation[];
55
+ /**
56
+ * Get validator description
57
+ */
58
+ getDescription(): string;
59
+ }
60
+ //# sourceMappingURL=subset-of-entity-fields-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subset-of-entity-fields-validator.d.ts","sourceRoot":"","sources":["../../../src/lib/constraint-validators/subset-of-entity-fields-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD;;;;;;;;;GASG;AACH,qBACa,6BAA8B,SAAQ,uBAAuB;IACxE;;;;;;OAMG;IACH,QAAQ,CACN,OAAO,EAAE,iBAAiB,EAC1B,UAAU,EAAE,kBAAkB,GAC7B,mBAAmB,EAAE;IAwMxB;;OAEG;IACH,cAAc,IAAI,MAAM;CAGzB"}
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * Subset Of Entity Fields Validator
4
+ *
5
+ * Validates that array elements are valid field names for a specified entity.
6
+ *
7
+ * This validator is essential for catching errors like:
8
+ * ```jsx
9
+ * // ❌ BROKEN - FullName, Status, StartDate don't exist on Members
10
+ * <EntityDataGrid
11
+ * entityName="Members"
12
+ * fields={['FullName', 'Status', 'StartDate']}
13
+ * />
14
+ *
15
+ * // ✅ FIXED - FirstName, LastName, Email exist on Members
16
+ * <EntityDataGrid
17
+ * entityName="Members"
18
+ * fields={['FirstName', 'LastName', 'Email']}
19
+ * />
20
+ * ```
21
+ *
22
+ * Constraint Definition:
23
+ * ```json
24
+ * {
25
+ * "type": "subset-of-entity-fields",
26
+ * "dependsOn": "entityName",
27
+ * "config": {
28
+ * "allowWildcard": false,
29
+ * "caseSensitive": false
30
+ * }
31
+ * }
32
+ * ```
33
+ */
34
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
35
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
36
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
37
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
38
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
39
+ };
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.SubsetOfEntityFieldsValidator = void 0;
42
+ const global_1 = require("@memberjunction/global");
43
+ const base_constraint_validator_1 = require("./base-constraint-validator");
44
+ /**
45
+ * Validates that array elements are valid field names for an entity
46
+ *
47
+ * **Depends On**: Entity name (from entityName prop)
48
+ * **Validates**: Array of field name strings
49
+ * **Common Use Cases**:
50
+ * - EntityDataGrid fields prop
51
+ * - DataGrid columns (when using entity binding)
52
+ * - Custom components with entity field arrays
53
+ */
54
+ let SubsetOfEntityFieldsValidator = class SubsetOfEntityFieldsValidator extends base_constraint_validator_1.BaseConstraintValidator {
55
+ /**
56
+ * Validate that array elements are valid entity field names
57
+ *
58
+ * @param context - Validation context
59
+ * @param constraint - Constraint definition
60
+ * @returns Array of violations (empty if valid)
61
+ */
62
+ validate(context, constraint) {
63
+ const violations = [];
64
+ // Check if value is dynamic (can't validate statically)
65
+ if (this.isDynamicValue(context.propertyValue)) {
66
+ return violations; // Skip validation
67
+ }
68
+ // Get the entity name from dependent prop
69
+ const entityName = this.getDependentPropValue(context, constraint);
70
+ if (!entityName || typeof entityName !== 'string') {
71
+ // Can't validate without entity name
72
+ return violations;
73
+ }
74
+ // Check if entity exists
75
+ if (!context.hasEntity(entityName)) {
76
+ // Entity doesn't exist - not this validator's responsibility to report
77
+ // (should be caught by valid-entity-reference validator)
78
+ return violations;
79
+ }
80
+ // Get entity fields
81
+ const entityFields = context.getEntityFields(entityName);
82
+ const fieldNames = entityFields.map((f) => f.name);
83
+ const fieldNamesLower = fieldNames.map((f) => f.toLowerCase());
84
+ // Extract config
85
+ const config = constraint.config || {};
86
+ const allowWildcard = config.allowWildcard === true;
87
+ const caseSensitive = config.caseSensitive === true;
88
+ // Validate the property value is an array
89
+ if (!Array.isArray(context.propertyValue)) {
90
+ violations.push(this.createViolation('invalid-type', this.applyErrorTemplate(constraint, context, `Property '${context.propertyName}' must be an array of field names`, { entityName }), 'critical', `Use an array: ${context.propertyName}={['${fieldNames.slice(0, 3).join("', '")}']}`));
91
+ return violations;
92
+ }
93
+ // Validate each element is a string or object with 'field' property
94
+ for (let i = 0; i < context.propertyValue.length; i++) {
95
+ const element = context.propertyValue[i];
96
+ // Skip dynamic values (identifiers, expressions)
97
+ if (this.isDynamicValue(element)) {
98
+ continue;
99
+ }
100
+ // Extract field name from element
101
+ let fieldName = null;
102
+ if (typeof element === 'string') {
103
+ // Simple string field name
104
+ fieldName = element;
105
+ }
106
+ else if (typeof element === 'object' && element !== null) {
107
+ // Object with 'field' property (e.g., ColumnDef, FieldDefinition)
108
+ const fieldProp = element.field;
109
+ if (typeof fieldProp === 'string') {
110
+ fieldName = fieldProp;
111
+ }
112
+ else if (this.isDynamicValue(fieldProp)) {
113
+ // Dynamic field property - skip validation
114
+ continue;
115
+ }
116
+ else {
117
+ // Object without valid 'field' property
118
+ violations.push(this.createViolation('invalid-element-type', this.applyErrorTemplate(constraint, context, `Element at index ${i} in '${context.propertyName}' must be a string or object with 'field' property`, { entityName, index: i, elementType: typeof element }), 'high', `Use string field names or objects with 'field' property from entity '${entityName}'`));
119
+ continue;
120
+ }
121
+ }
122
+ else {
123
+ // Invalid type (not string or object)
124
+ violations.push(this.createViolation('invalid-element-type', this.applyErrorTemplate(constraint, context, `Element at index ${i} in '${context.propertyName}' must be a string or object, got ${typeof element}`, { entityName, index: i, elementType: typeof element }), 'high', `Use string field names from entity '${entityName}'`));
125
+ continue;
126
+ }
127
+ // At this point, fieldName should be a string
128
+ if (!fieldName) {
129
+ continue; // Should not reach here, but safety check
130
+ }
131
+ // Check for wildcard
132
+ if (allowWildcard && fieldName === '*') {
133
+ continue; // Wildcard is allowed
134
+ }
135
+ // Check if field exists
136
+ let fieldExists = false;
137
+ let correctCaseName = null;
138
+ if (caseSensitive) {
139
+ fieldExists = fieldNames.includes(fieldName);
140
+ }
141
+ else {
142
+ // Case-insensitive check
143
+ const index = fieldNamesLower.indexOf(fieldName.toLowerCase());
144
+ fieldExists = index !== -1;
145
+ if (fieldExists) {
146
+ correctCaseName = fieldNames[index];
147
+ }
148
+ }
149
+ if (!fieldExists) {
150
+ // Field doesn't exist - find similar fields for suggestion
151
+ const similarFields = this.findSimilar(fieldName, fieldNames, 3, 3);
152
+ let suggestion = '';
153
+ if (similarFields.length > 0) {
154
+ suggestion = `Did you mean: ${this.formatValueList(similarFields, 3)}?`;
155
+ }
156
+ else {
157
+ suggestion = `Available fields: ${this.formatValueList(fieldNames, 10)}`;
158
+ }
159
+ violations.push(this.createViolation('invalid-field', this.applyErrorTemplate(constraint, context, `Field '${fieldName}' does not exist on entity '${entityName}'`, {
160
+ field: fieldName,
161
+ entityName,
162
+ availableFields: fieldNames.slice(0, 10).join(', '),
163
+ }), 'critical', suggestion, {
164
+ field: fieldName,
165
+ entityName,
166
+ index: i,
167
+ availableFields: fieldNames,
168
+ similarFields,
169
+ }));
170
+ }
171
+ else if (!caseSensitive && correctCaseName && correctCaseName !== fieldName) {
172
+ // Field exists but case doesn't match
173
+ violations.push(this.createViolation('case-mismatch', this.applyErrorTemplate(constraint, context, `Field '${fieldName}' case doesn't match schema. Expected '${correctCaseName}' on entity '${entityName}'`, {
174
+ field: fieldName,
175
+ correctCase: correctCaseName,
176
+ entityName,
177
+ }), 'medium', `Use '${correctCaseName}' instead of '${fieldName}'`, {
178
+ field: fieldName,
179
+ correctCase: correctCaseName,
180
+ entityName,
181
+ index: i,
182
+ }));
183
+ }
184
+ }
185
+ return violations;
186
+ }
187
+ /**
188
+ * Get validator description
189
+ */
190
+ getDescription() {
191
+ return 'Validates that array elements are valid field names for the specified entity';
192
+ }
193
+ };
194
+ exports.SubsetOfEntityFieldsValidator = SubsetOfEntityFieldsValidator;
195
+ exports.SubsetOfEntityFieldsValidator = SubsetOfEntityFieldsValidator = __decorate([
196
+ (0, global_1.RegisterClass)(base_constraint_validator_1.BaseConstraintValidator, 'subset-of-entity-fields')
197
+ ], SubsetOfEntityFieldsValidator);
198
+ //# sourceMappingURL=subset-of-entity-fields-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subset-of-entity-fields-validator.js","sourceRoot":"","sources":["../../../src/lib/constraint-validators/subset-of-entity-fields-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Validation Context
3
+ *
4
+ * Provides all the information a constraint validator needs to perform validation.
5
+ * This context is passed to validators by the linter rule and includes:
6
+ * - AST node and path information for location tracking
7
+ * - Component spec for type lookups
8
+ * - Sibling props for dependency resolution
9
+ * - Entity/query metadata from data requirements
10
+ * - Helper methods for common validation tasks
11
+ */
12
+ import * as t from '@babel/types';
13
+ import { NodePath } from '@babel/traverse';
14
+ import { ComponentSpec } from '@memberjunction/interactive-component-types';
15
+ import { TypeInferenceEngine } from '../type-inference-engine';
16
+ import { ExtractedValue } from '../prop-value-extractor';
17
+ /**
18
+ * Context object passed to constraint validators
19
+ *
20
+ * Contains all information needed to validate a prop value against constraints.
21
+ */
22
+ export interface ValidationContext {
23
+ /**
24
+ * The AST node being validated
25
+ *
26
+ * This is typically the JSXAttribute node, but validators can traverse
27
+ * to child nodes for more specific location information.
28
+ */
29
+ node: t.Node;
30
+ /**
31
+ * Babel traversal path for the node
32
+ *
33
+ * Provides access to parent nodes, scope information, and AST manipulation.
34
+ * Validators should not modify the AST - this is read-only validation.
35
+ */
36
+ path: NodePath<any>;
37
+ /**
38
+ * Name of the component being validated
39
+ *
40
+ * Example: "DataGrid", "EntityDataGrid", "SimpleChart"
41
+ */
42
+ componentName: string;
43
+ /**
44
+ * Full component specification
45
+ *
46
+ * Provides access to:
47
+ * - Type definitions (for custom type validation)
48
+ * - Data requirements (entities, queries)
49
+ * - Other properties (for cross-property validation)
50
+ * - Dependency specs (for validating nested components)
51
+ */
52
+ componentSpec: ComponentSpec;
53
+ /**
54
+ * Name of the property being validated
55
+ *
56
+ * Example: "fields", "columns", "entityName", "extraFilter"
57
+ */
58
+ propertyName: string;
59
+ /**
60
+ * Extracted value of the property
61
+ *
62
+ * This is the result of PropValueExtractor.extract() and can be:
63
+ * - Primitive: string, number, boolean, null
64
+ * - Array: Array of extracted values
65
+ * - Object: Record<string, ExtractedValue>
66
+ * - DynamicValue: { _type: 'identifier' | 'expression', name?, description? }
67
+ *
68
+ * If the value is a DynamicValue, validators should typically skip validation
69
+ * and return an empty violations array (the linter will warn the user).
70
+ */
71
+ propertyValue: ExtractedValue;
72
+ /**
73
+ * Map of sibling props on the same JSX element
74
+ *
75
+ * Key is prop name, value is extracted value.
76
+ * Used for constraints with `dependsOn` to access related prop values.
77
+ *
78
+ * Example:
79
+ * ```typescript
80
+ * // <EntityDataGrid entityName="Members" fields={['FirstName', 'LastName']} />
81
+ * siblingProps.get('entityName') // => "Members"
82
+ * siblingProps.get('fields') // => ['FirstName', 'LastName']
83
+ * ```
84
+ */
85
+ siblingProps: Map<string, ExtractedValue>;
86
+ /**
87
+ * Map of entity name to entity metadata
88
+ *
89
+ * Populated from componentSpec.dataRequirements.entities
90
+ * Used by validators that check field names, entity references, etc.
91
+ *
92
+ * Example:
93
+ * ```typescript
94
+ * const memberEntity = entities.get('Members');
95
+ * const fields = memberEntity.fields; // Array of EntityFieldInfo
96
+ * ```
97
+ */
98
+ entities: Map<string, EntityMetadata>;
99
+ /**
100
+ * Map of query name to query metadata
101
+ *
102
+ * Populated from componentSpec.dataRequirements.queries
103
+ * Used by validators that check query references and parameters.
104
+ *
105
+ * Example:
106
+ * ```typescript
107
+ * const query = queries.get('Sales by Region');
108
+ * const params = query.parameters; // Array of QueryParameter
109
+ * ```
110
+ */
111
+ queries: Map<string, QueryMetadata>;
112
+ /**
113
+ * Type inference engine for checking expression types
114
+ *
115
+ * Used for advanced type checking beyond what PropValueExtractor provides.
116
+ * Can infer types of variables, function calls, etc.
117
+ */
118
+ typeEngine: TypeInferenceEngine;
119
+ /**
120
+ * Get field metadata for an entity
121
+ *
122
+ * @param entityName - Name of the entity
123
+ * @returns Array of field info, or empty array if entity not found
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const fields = context.getEntityFields('Members');
128
+ * const fieldNames = fields.map(f => f.name);
129
+ * ```
130
+ */
131
+ getEntityFields(entityName: string): EntityFieldInfo[];
132
+ /**
133
+ * Get the data type of a specific field on an entity
134
+ *
135
+ * @param entityName - Name of the entity
136
+ * @param fieldName - Name of the field
137
+ * @returns Data type string (e.g., 'string', 'number', 'date'), or null if not found
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * const fieldType = context.getEntityFieldType('Members', 'JoinDate');
142
+ * // => 'date'
143
+ * ```
144
+ */
145
+ getEntityFieldType(entityName: string, fieldName: string): string | null;
146
+ /**
147
+ * Find field names similar to the given field name (for suggestions)
148
+ *
149
+ * Uses fuzzy matching (Levenshtein distance or similar) to find close matches.
150
+ * Useful for "Did you mean?" error messages.
151
+ *
152
+ * @param fieldName - The field name to find matches for
153
+ * @param entityName - Name of the entity to search in
154
+ * @param maxResults - Maximum number of suggestions (default: 3)
155
+ * @returns Array of similar field names, sorted by similarity
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * const suggestions = context.findSimilarFieldNames('FristName', 'Members', 3);
160
+ * // => ['FirstName', 'FirstNameNormalized', 'FirstNameMasked']
161
+ * ```
162
+ */
163
+ findSimilarFieldNames(fieldName: string, entityName: string, maxResults?: number): string[];
164
+ /**
165
+ * Get parameter metadata for a query
166
+ *
167
+ * @param queryName - Name of the query
168
+ * @returns Array of parameter info, or empty array if query not found
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * const params = context.getQueryParameters('Sales by Region');
173
+ * const requiredParams = params.filter(p => p.required);
174
+ * ```
175
+ */
176
+ getQueryParameters(queryName: string): QueryParameter[];
177
+ /**
178
+ * Check if a query exists in the component's data requirements
179
+ *
180
+ * @param queryName - Name of the query to check
181
+ * @param categoryPath - Optional category path for disambiguation
182
+ * @returns True if the query exists
183
+ *
184
+ * @example
185
+ * ```typescript
186
+ * if (!context.hasQuery('Sales Report', '/Reports/Sales')) {
187
+ * // Query not found
188
+ * }
189
+ * ```
190
+ */
191
+ hasQuery(queryName: string, categoryPath?: string): boolean;
192
+ /**
193
+ * Check if an entity exists in the component's data requirements
194
+ *
195
+ * @param entityName - Name of the entity to check
196
+ * @returns True if the entity exists
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * if (!context.hasEntity('Members')) {
201
+ * // Entity not found
202
+ * }
203
+ * ```
204
+ */
205
+ hasEntity(entityName: string): boolean;
206
+ }
207
+ /**
208
+ * Entity metadata extracted from data requirements
209
+ */
210
+ export interface EntityMetadata {
211
+ /**
212
+ * Entity name
213
+ */
214
+ name: string;
215
+ /**
216
+ * Entity description (if available)
217
+ */
218
+ description?: string;
219
+ /**
220
+ * Array of field metadata for this entity
221
+ */
222
+ fields: EntityFieldInfo[];
223
+ /**
224
+ * Primary key field name(s)
225
+ */
226
+ primaryKeys?: string[];
227
+ }
228
+ /**
229
+ * Field metadata for an entity
230
+ */
231
+ export interface EntityFieldInfo {
232
+ /**
233
+ * Field name
234
+ */
235
+ name: string;
236
+ /**
237
+ * Data type (e.g., 'string', 'number', 'date', 'boolean')
238
+ */
239
+ type: string;
240
+ /**
241
+ * SQL data type (e.g., 'nvarchar', 'int', 'datetime', 'bit')
242
+ */
243
+ sqlType?: string;
244
+ /**
245
+ * Whether this field is required (NOT NULL)
246
+ */
247
+ required?: boolean;
248
+ /**
249
+ * Field description (if available)
250
+ */
251
+ description?: string;
252
+ /**
253
+ * Whether this is a primary key field
254
+ */
255
+ isPrimaryKey?: boolean;
256
+ /**
257
+ * If this is a foreign key, the related entity name
258
+ */
259
+ relatedEntity?: string;
260
+ /**
261
+ * Maximum length for string fields
262
+ */
263
+ maxLength?: number;
264
+ }
265
+ /**
266
+ * Query metadata extracted from data requirements
267
+ */
268
+ export interface QueryMetadata {
269
+ /**
270
+ * Query name
271
+ */
272
+ name: string;
273
+ /**
274
+ * Query description (if available)
275
+ */
276
+ description?: string;
277
+ /**
278
+ * Category path for disambiguation
279
+ */
280
+ categoryPath?: string;
281
+ /**
282
+ * Array of parameter metadata for this query
283
+ */
284
+ parameters: QueryParameter[];
285
+ /**
286
+ * Expected result fields (if specified)
287
+ */
288
+ resultFields?: Array<{
289
+ name: string;
290
+ type: string;
291
+ }>;
292
+ }
293
+ /**
294
+ * Parameter metadata for a query
295
+ */
296
+ export interface QueryParameter {
297
+ /**
298
+ * Parameter name
299
+ */
300
+ name: string;
301
+ /**
302
+ * Parameter data type
303
+ */
304
+ type: string;
305
+ /**
306
+ * SQL data type
307
+ */
308
+ sqlType?: string;
309
+ /**
310
+ * Whether this parameter is required
311
+ */
312
+ required?: boolean;
313
+ /**
314
+ * Default value if not provided
315
+ */
316
+ defaultValue?: any;
317
+ /**
318
+ * Example/test value for documentation
319
+ */
320
+ testValue?: any;
321
+ /**
322
+ * Parameter description (if available)
323
+ */
324
+ description?: string;
325
+ }
326
+ //# sourceMappingURL=validation-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-context.d.ts","sourceRoot":"","sources":["../../../src/lib/constraint-validators/validation-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * Validation Context
4
+ *
5
+ * Provides all the information a constraint validator needs to perform validation.
6
+ * This context is passed to validators by the linter rule and includes:
7
+ * - AST node and path information for location tracking
8
+ * - Component spec for type lookups
9
+ * - Sibling props for dependency resolution
10
+ * - Entity/query metadata from data requirements
11
+ * - Helper methods for common validation tasks
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ //# sourceMappingURL=validation-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-context.js","sourceRoot":"","sources":["../../../src/lib/constraint-validators/validation-context.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG"}