118 lines
2.9 KiB
JavaScript
118 lines
2.9 KiB
JavaScript
|
|
import { BaseNode } from './BaseNode.js';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* AST node for evidence definitions
|
||
|
|
* Represents: evidence canRead(user: User, doc: Document) { ... } PROVIDES string
|
||
|
|
*/
|
||
|
|
export class EvidenceNode extends BaseNode {
|
||
|
|
constructor(name, location = null) {
|
||
|
|
super('Evidence', location);
|
||
|
|
this.name = name;
|
||
|
|
this.parameters = [];
|
||
|
|
this.returnType = null;
|
||
|
|
this.body = null; // EvidenceBodyNode
|
||
|
|
this.provides = null; // Return type specification
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Add a parameter to the evidence
|
||
|
|
* @param {ParameterNode} parameter - Parameter to add
|
||
|
|
*/
|
||
|
|
addParameter(parameter) {
|
||
|
|
this.parameters.push(parameter);
|
||
|
|
this.addChild(parameter);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set the body of the evidence
|
||
|
|
* @param {EvidenceBodyNode} body - Evidence body
|
||
|
|
*/
|
||
|
|
setBody(body) {
|
||
|
|
this.body = body;
|
||
|
|
this.addChild(body);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set the return type for this evidence
|
||
|
|
* @param {string} returnType - Return type
|
||
|
|
*/
|
||
|
|
setReturnType(returnType) {
|
||
|
|
this.returnType = returnType;
|
||
|
|
this.provides = returnType;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the parameter names as an array
|
||
|
|
* @returns {string[]} Array of parameter names
|
||
|
|
*/
|
||
|
|
getParameterNames() {
|
||
|
|
return this.parameters.map(param => param.name);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the parameter types as an array
|
||
|
|
* @returns {string[]} Array of parameter types
|
||
|
|
*/
|
||
|
|
getParameterTypes() {
|
||
|
|
return this.parameters.map(param => param.type);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Find a parameter by name
|
||
|
|
* @param {string} name - Parameter name to find
|
||
|
|
* @returns {ParameterNode|null} Found parameter or null
|
||
|
|
*/
|
||
|
|
getParameter(name) {
|
||
|
|
return this.parameters.find(param => param.name === name) || null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the signature string for this evidence
|
||
|
|
* @returns {string} Evidence signature
|
||
|
|
*/
|
||
|
|
getSignature() {
|
||
|
|
const paramStr = this.parameters.map(param => `${param.name}: ${param.type}`).join(', ');
|
||
|
|
return `${this.name}(${paramStr})`;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if this evidence has a return type
|
||
|
|
* @returns {boolean} True if has return type
|
||
|
|
*/
|
||
|
|
hasReturnType() {
|
||
|
|
return this.returnType !== null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Validate the evidence
|
||
|
|
* @returns {string[]} Array of error messages
|
||
|
|
*/
|
||
|
|
validate() {
|
||
|
|
const errors = [];
|
||
|
|
|
||
|
|
// Validate evidence name
|
||
|
|
if (!this.name || typeof this.name !== 'string') {
|
||
|
|
errors.push(`Invalid evidence name: ${this.name}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Validate parameters
|
||
|
|
this.parameters.forEach((param, index) => {
|
||
|
|
const paramErrors = param.validate ? param.validate() : [];
|
||
|
|
errors.push(...paramErrors.map(err => `Parameter ${index + 1}: ${err}`));
|
||
|
|
});
|
||
|
|
|
||
|
|
// Validate body
|
||
|
|
if (this.body) {
|
||
|
|
const bodyErrors = this.body.validate ? this.body.validate() : [];
|
||
|
|
errors.push(...bodyErrors);
|
||
|
|
}
|
||
|
|
|
||
|
|
return errors;
|
||
|
|
}
|
||
|
|
|
||
|
|
toString() {
|
||
|
|
const providesStr = this.returnType ? ` PROVIDES ${this.returnType}` : '';
|
||
|
|
return `Evidence(${this.getSignature()}${providesStr})`;
|
||
|
|
}
|
||
|
|
}
|