Four defects found by dogfooding Speckl against the v0.3 product-layer spec (FederatedMeetupProduct.speckdl, 74 members): D1 — CRITICAL: List<T> fields in interface records emitted empty type Root cause: interface record fields called speckTypeToProto(f.type.name) which returns '' for List/Map/Set types (their .name is undefined). Event and state fields had inline List/Map dispatch, but interfaces did not. Fix: extracted typeExprToProto() shared function that handles all TypeExpr variants (primitive, ident, list, map, set). All four field-emitting code paths (interfaces, events, state, transitions) now use it. D2 — MODERATE: Transition type discriminator field silently dropped Root cause: parser stores the type field in t.typeDiscriminator (string) rather than in t.fields array. Generator only emitted t.fields. Fix: emit typeDiscriminator as 'type' field at number 1, offset other fields by 1 to avoid collision. D4 — LOW: Enum variant name collisions across enums in same proto scope Proto3 requires all enum values unique within enclosing scope, not just the enum. PENDING in Role and PENDING in OrderStatus collided. Fix: prefix all variants with upperSnake(enumName) — the proto3 convention. This also matches the handwritten proto's naming (TRANSITION_TYPE_*). D5 — LOW: Date in interface fields did not trigger timestamp import The usesTimestamp check only scanned events and state, not interfaces. Fix: added interface member check to the timestamp import scan. D3 (deferred): rc_ typo in spec source silently swallowed by parser. Parser bug, not generator bug. Filed for future cycle. Verified: 56/56 tests pass, both FederatedMeetup.speckdl and FederatedMeetupProduct.speckdl compile to protoc-clean output.
227 lines
No EOL
4.9 KiB
TypeScript
227 lines
No EOL
4.9 KiB
TypeScript
export interface SpeckNode {
|
|
type: 'speck';
|
|
name: string;
|
|
members: MemberNode[];
|
|
version?: string;
|
|
author?: string;
|
|
license?: string;
|
|
protoPackage?: string;
|
|
goPackage?: string;
|
|
eventSuffix?: string;
|
|
}
|
|
export interface ImportNode {
|
|
type: 'import';
|
|
path: string;
|
|
alias?: string;
|
|
version?: string;
|
|
hash?: string;
|
|
}
|
|
export interface InputNode {
|
|
type: 'input';
|
|
typeExpr: TypeExpr;
|
|
}
|
|
export interface OutputNode {
|
|
type: 'output';
|
|
typeExpr: TypeExpr;
|
|
}
|
|
export interface ConstraintNode {
|
|
type: 'constraint';
|
|
name?: string;
|
|
expr: string;
|
|
}
|
|
export interface VerifyNode {
|
|
type: 'verify';
|
|
name: string;
|
|
temporalExpr: string;
|
|
depth?: number;
|
|
}
|
|
export interface InterfaceField {
|
|
name: string;
|
|
type: TypeExpr;
|
|
}
|
|
export interface RpcMethod {
|
|
name: string;
|
|
requestType: string;
|
|
responseType: string;
|
|
clientStreaming?: boolean;
|
|
serverStreaming?: boolean;
|
|
}
|
|
export interface ServiceNode {
|
|
type: 'service';
|
|
name: string;
|
|
rpcs: RpcMethod[];
|
|
}
|
|
export interface InterfaceNode {
|
|
type: 'interface';
|
|
name: string;
|
|
kind: 'enum' | 'record' | 'service' | 'mixed';
|
|
methods: MethodSignature[];
|
|
fields: InterfaceField[];
|
|
}
|
|
export interface MethodSignature {
|
|
name: string;
|
|
params: {
|
|
name: string;
|
|
type: TypeExpr;
|
|
}[];
|
|
returnType: TypeExpr;
|
|
}
|
|
export interface EventNode {
|
|
type: 'event';
|
|
name: string;
|
|
fields: {
|
|
name: string;
|
|
type: TypeExpr;
|
|
}[];
|
|
}
|
|
export interface OneofNode {
|
|
type: 'oneof';
|
|
name: string;
|
|
variants: OneofVariant[];
|
|
}
|
|
export interface OneofVariant {
|
|
fieldName: string;
|
|
typeName: string;
|
|
}
|
|
export interface TransitionNode {
|
|
type: 'transition';
|
|
name: string;
|
|
fields: TransitionField[];
|
|
payloadOneof?: string;
|
|
typeDiscriminator?: string;
|
|
}
|
|
export interface TransitionField {
|
|
name: string;
|
|
type: TypeExpr;
|
|
}
|
|
export interface ProvenanceNode {
|
|
type: 'provenance';
|
|
clauses: ProvenanceClause[];
|
|
}
|
|
export interface ProvenanceClause {
|
|
type: 'regulation' | 'design_decision' | 'parent_spec' | 'external_doc';
|
|
value: string;
|
|
location?: string;
|
|
}
|
|
export interface ReviewNode {
|
|
type: 'review';
|
|
kind: 'manual' | 'auto' | 'hybrid';
|
|
}
|
|
export interface DerivesNode {
|
|
type: 'derives';
|
|
from: string;
|
|
via?: string;
|
|
}
|
|
export interface SatisfiesNode {
|
|
type: 'satisfies';
|
|
requirement: string;
|
|
clause?: string;
|
|
}
|
|
export interface AuthorNode {
|
|
type: 'author';
|
|
name: string;
|
|
email?: string;
|
|
}
|
|
export interface SourceNode {
|
|
type: 'source';
|
|
kind: 'conversation' | 'meeting' | 'document' | 'regulation' | 'architecture_review' | 'threat_model' | 'compliance_audit';
|
|
ref?: string;
|
|
}
|
|
export interface BOMNode {
|
|
type: 'bom';
|
|
compiler?: {
|
|
name: string;
|
|
version?: string;
|
|
};
|
|
solver?: {
|
|
name: string;
|
|
version?: string;
|
|
};
|
|
runtime?: {
|
|
name: string;
|
|
version?: string;
|
|
};
|
|
license?: string;
|
|
hash?: string;
|
|
}
|
|
export interface StateNode {
|
|
type: 'state';
|
|
variables: StateVar[];
|
|
messageName?: string;
|
|
}
|
|
export interface StateVar {
|
|
name: string;
|
|
typeExpr: TypeExpr;
|
|
defaultInit?: string;
|
|
}
|
|
export interface InitNode {
|
|
type: 'init';
|
|
assignments: {
|
|
name: string;
|
|
expr: string;
|
|
}[];
|
|
}
|
|
export interface ActionNode {
|
|
type: 'action';
|
|
name: string;
|
|
params: {
|
|
name: string;
|
|
type: TypeExpr;
|
|
}[];
|
|
statements: ActionStatement[];
|
|
}
|
|
export type ActionStatement = {
|
|
type: 'assign';
|
|
target: string;
|
|
expr: string;
|
|
} | {
|
|
type: 'let';
|
|
name: string;
|
|
expr: string;
|
|
} | {
|
|
type: 'require';
|
|
expr: string;
|
|
} | {
|
|
type: 'precondition';
|
|
expr: string;
|
|
} | {
|
|
type: 'postcondition';
|
|
expr: string;
|
|
} | {
|
|
type: 'emit';
|
|
event: string;
|
|
fields: {
|
|
name: string;
|
|
value: string;
|
|
}[];
|
|
} | {
|
|
type: 'return';
|
|
expr: string;
|
|
} | {
|
|
type: 'ifblock';
|
|
raw: string;
|
|
};
|
|
export type MemberNode = ImportNode | InputNode | OutputNode | ConstraintNode | VerifyNode | InterfaceNode | EventNode | OneofNode | TransitionNode | ProvenanceNode | ReviewNode | DerivesNode | SatisfiesNode | AuthorNode | SourceNode | BOMNode | StateNode | InitNode | ActionNode | ServiceNode;
|
|
export interface TypeExpr {
|
|
type: 'primitive' | 'record' | 'list' | 'set' | 'map' | 'ident';
|
|
name?: string;
|
|
fields?: {
|
|
name: string;
|
|
type: TypeExpr;
|
|
}[];
|
|
elementType?: TypeExpr;
|
|
keyType?: TypeExpr;
|
|
valueType?: TypeExpr;
|
|
}
|
|
export interface AST {
|
|
specks: SpeckNode[];
|
|
}
|
|
/**
|
|
* Parse a .speck file and return the AST
|
|
*/
|
|
export declare function parseSpeckFile(filePath: string): AST;
|
|
/**
|
|
* Parse SpeckDL content and return the AST
|
|
*/
|
|
export declare function parseSpeckContent(content: string, filePath?: string): AST;
|
|
//# sourceMappingURL=parser.d.ts.map
|