Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions packages/core/src/domain-activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@ export class DirectiveDetector implements DomainDetector {
lines.forEach((line, _index) => {
// Detect explicit @domain: directives
const domainMatch = line.match(/@domain:\s*([a-zA-Z0-9-_]+)/);
if (domainMatch) {
results.push({
domain: domainMatch[1],
confidence: 1.0,
source: 'directive',
line: _index + 1
});
if (domainMatch) {
results.push({
domain: domainMatch[1]!,
confidence: 1.0,
source: 'directive',
line: _index + 1
});
}

// Detect domain-prefixed directives (@c4:, @k8s:, @bpmn:)
const prefixMatch = line.match(/@([a-zA-Z0-9-_]+):/);
if (prefixMatch) {
const domain = prefixMatch[1];
const domain = prefixMatch[1]!;
// Skip common non-domain directives and the 'domain' keyword itself
if (!['level', 'style', 'nav', 'link', 'docs', 'domain'].includes(domain)) {
results.push({
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export class LayerFlowGraph {
throw new Error(`Node with ID "${id}" not found. Check the node ID or create the node first.`);
}

const currentNode = this.ast.nodes[nodeIndex];
const currentNode = this.ast.nodes[nodeIndex]!;

// Validate label if being updated
if (updates.label !== undefined && (!updates.label || updates.label.trim() === '')) {
Expand Down Expand Up @@ -316,9 +316,9 @@ export class LayerFlowGraph {
...currentNode,
...updates,
...(mergedMetadata && { metadata: mergedMetadata })
};
} as GraphNode;

const updatedNode = deepClone(this.ast.nodes[nodeIndex]);
const updatedNode = deepClone(this.ast.nodes[nodeIndex]) as GraphNode;

// Emit after hook
this.emitHook('node:afterUpdate', updatedNode);
Expand Down Expand Up @@ -644,9 +644,9 @@ export class LayerFlowGraph {
this.ast.layers[layerIndex] = {
...this.ast.layers[layerIndex],
...updates
};
} as LayerDefinition;

return deepClone(this.ast.layers[layerIndex]);
return deepClone(this.ast.layers[layerIndex]) as LayerDefinition;
}

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export interface GraphNode {
id: string;
/** Human-readable label for the node */
label: string;
/** Optional legacy name field */
name?: string;
/** Type classification of the node (e.g., 'service', 'database', 'frontend') */
type?: string;
/** Layer level for hierarchical organization (0-based) */
Expand All @@ -28,6 +30,8 @@ export interface GraphNode {
* @public
*/
export interface Edge {
/** Optional identifier for the edge */
id?: string;
/** Source node identifier */
from: string;
/** Target node identifier */
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,10 +548,12 @@ export class GraphValidator {

// Check for gaps in level sequence
for (let i = 1; i < levels.length; i++) {
if (levels[i] - levels[i - 1] > 1) {
const current = levels[i]!;
const previous = levels[i - 1]!;
if (current - previous > 1) {
warnings.push(this.createWarning(
'LEVEL_GAP',
`Gap in layer levels: missing level ${levels[i - 1] + 1}`,
`Gap in layer levels: missing level ${previous + 1}`,
'nodes'
));
}
Expand Down
31 changes: 25 additions & 6 deletions packages/parser/src/ast-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,12 @@ export class EnhancedASTConverter {
conversionTime: number;
totalTime: number;
};
/** Legacy success flag */
success?: boolean;
/** Legacy graph alias for ast */
graph?: GraphAST | null;
/** Optional debug info */
debugInfo?: Record<string, any>;
} {
const startTime = performance.now();
ConversionLogger.time('Total Conversion');
Expand All @@ -727,7 +733,11 @@ export class EnhancedASTConverter {
defaultNodeType: options.defaultNodeType || 'component',
defaultEdgeType: options.defaultEdgeType || 'connection',
preserveLFFMetadata: options.preserveLFFMetadata ?? true,
generateUniqueIds: options.generateUniqueIds ?? true
generateUniqueIds: options.generateUniqueIds ?? options.generateIds ?? true,
strictMode: options.strictMode ?? false,
preserveSourceLocations: options.preserveSourceLocations ?? false,
debugMode: options.debugMode ?? false,
generateIds: options.generateIds ?? options.generateUniqueIds ?? true
};

// Phase 1: Validation
Expand All @@ -739,7 +749,9 @@ export class EnhancedASTConverter {
return {
ast: null,
errors: validation.errors,
warnings: validation.warnings
warnings: validation.warnings,
success: false,
graph: null
};
}

Expand Down Expand Up @@ -792,15 +804,18 @@ export class EnhancedASTConverter {
ConversionLogger.timeEnd('Total Conversion');
ConversionLogger.debug(`Conversion complete: ${nodes.length} nodes, ${edges.length} edges`);

const ast: GraphAST = { nodes, edges, metadata };
return {
ast: { nodes, edges, metadata },
ast,
errors: [],
warnings: validation.warnings,
metrics: {
validationTime: conversionStart - startTime,
conversionTime,
totalTime
}
},
success: true,
graph: ast
};

} catch (error) {
Expand All @@ -817,7 +832,9 @@ export class EnhancedASTConverter {
return {
ast: null,
errors: [conversionError],
warnings: validation.warnings
warnings: validation.warnings,
success: false,
graph: null
};
}
}
Expand Down Expand Up @@ -886,4 +903,6 @@ export function convertLFFToCoreWithValidation(
*/
export function createConverter(): EnhancedASTConverter {
return new EnhancedASTConverter();
}
}
export { EnhancedASTConverter as ASTConverter };

13 changes: 7 additions & 6 deletions packages/parser/src/cst-to-ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ interface ConversionContext {
/**
* Modular CST to LFF AST converter with discriminated union support
*/
class CSTToLFFConverter {
export class CSTToLFFConverter {
private context: ConversionContext;

constructor(sourceText: string) {
Expand All @@ -59,7 +59,7 @@ class CSTToLFFConverter {
/**
* Main conversion entry point
*/
convert(cst: CSTNode): LFFQ {
convert(cst: CSTNode): { success: boolean; ast?: LFFQ; errors: ParseError[] } {
const result: LFFQ = {
nodes: [],
edges: [],
Expand All @@ -72,11 +72,11 @@ class CSTToLFFConverter {
};

if (!cst?.children) {
return result;
return { success: result.errors.length === 0, ast: result, errors: result.errors };
}

this.convertDocument(cst, result);
return result;
return { success: result.errors.length === 0, ast: result, errors: result.errors };
}

/**
Expand Down Expand Up @@ -677,7 +677,8 @@ class LocationHelper {
*
* @public
*/
export function convertCSTToLFF(cst: any, sourceText: string): LFFQ {
export function convertCSTToLFF(cst: any, sourceText: string): { success: boolean; ast?: LFFQ; errors: ParseError[] } {
const converter = new CSTToLFFConverter(sourceText);
return converter.convert(cst);
}
} export { CSTToLFFConverter as CSTToASTConverter };

32 changes: 28 additions & 4 deletions packages/parser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,11 @@ export function parseToCore(
const parseStart = performance.now();
const parser = new LFFParser();
parser.setLexer(lexer);
const cst = parser.parseToCST(text);
const cstResult = parser.parseToCST(text);

// Convert CST to LFF AST
const lffAST = convertCSTToLFF(cst, text);
const lffResult = convertCSTToLFF(cstResult.cst, text);
const lffAST = lffResult.ast || { nodes: [], edges: [], directives: [], errors: lffResult.errors, sourceInfo: { text, lines: text.split('\n') } };

// Add comments if requested
if (includeComments) {
Expand Down Expand Up @@ -261,6 +262,8 @@ export function parseToCore(

if (conversionResult.ast) {
result.coreAST = conversionResult.ast;
// Temporary compatibility alias for older tests
(result as ParseResult).ast = conversionResult.ast;
}

if (enableMetrics) {
Expand Down Expand Up @@ -407,6 +410,27 @@ export function parseWithPlugins(
return graph;
}

// ---------------------------------------------------------------------------
// Legacy compatibility helpers
// ---------------------------------------------------------------------------

/**
* Legacy alias for parseToCore
* @public
*/
export const parseLFF = parseToCore;

/**
* Create a parser instance with lexer preconfigured
* @public
*/
export function createParser(options: ParserOptions & ConversionOptions = {}): LFFParser & { parse: typeof parseToCore } {
const parser = new LFFParser();
parser.setLexer(new LFFLexer());
(parser as any).parse = (text: string) => parseToCore(text, options);
return parser as LFFParser & { parse: typeof parseToCore };
}

// ============================================================================
// Default Export for Convenience
// ============================================================================
Expand All @@ -415,4 +439,4 @@ export function parseWithPlugins(
* Default export providing the most commonly used parsing function
* @public
*/
export default parseToCore;
export default parseToCore;
31 changes: 30 additions & 1 deletion packages/parser/src/lff-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ export interface LFFSerializerOptions {
};
}

// Backwards compatibility aliases
export type SerializationOptions = LFFSerializerOptions;

/**
* Internal structure representation before formatting
* @private
Expand Down Expand Up @@ -701,6 +704,24 @@ export class EnhancedLFFSerializer {
// Format structure
return this.formatter.formatStructure(structure);
}

/**
* Serialize graph and provide metrics
*/
serializeWithMetrics(graph: GraphAST): { serialized: string; metrics: { serializationTime: number; outputSize: number; nodeCount: number; edgeCount: number } } {
const start = performance.now();
const serialized = this.serialize(graph);
const serializationTime = performance.now() - start;
return {
serialized,
metrics: {
serializationTime,
outputSize: serialized.length,
nodeCount: graph.nodes.length,
edgeCount: graph.edges.length
}
};
}

/**
* Update serializer options
Expand All @@ -717,6 +738,13 @@ export class EnhancedLFFSerializer {
getOptions(): LFFSerializerOptions {
return { ...this.options };
}

/**
* Validate serialization round-trip
*/
validateRoundTrip(graph: GraphAST, serialized: string) {
return validateRoundTrip(graph, serialized);
}
}

// ============================================================================
Expand Down Expand Up @@ -790,6 +818,7 @@ export const LFFFormattingPresets = {
sorting: { nodes: true, edges: true, directives: true }
} satisfies LFFSerializerOptions
};
export const FormattingPresets = LFFFormattingPresets;

// ============================================================================
// Public API
Expand Down Expand Up @@ -851,4 +880,4 @@ export function validateRoundTrip(_graph: GraphAST, _serialized: string): {
valid: true,
errors: []
};
}
}
20 changes: 19 additions & 1 deletion packages/parser/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,18 @@ export interface ConversionOptions {
* When true: ensures all nodes have unique identifiers
*/
generateUniqueIds?: boolean;

/** @deprecated Use generateUniqueIds */
generateIds?: boolean;

/** Enable strict validation mode */
strictMode?: boolean;

/** Preserve source locations in output (legacy option) */
preserveSourceLocations?: boolean;

/** Enable debug mode with extra diagnostics */
debugMode?: boolean;
}

/**
Expand All @@ -493,8 +505,14 @@ export interface ParseResult {
/**
* Converted Core AST ready for graph operations
* Optional: only present when conversion succeeds
*/
*/
coreAST?: GraphAST;

/**
* Legacy alias for `coreAST` used in older tests and integrations
* @deprecated Use `coreAST` instead
*/
ast?: GraphAST;

/** All errors encountered during parsing and conversion */
errors: ParseError[];
Expand Down
Loading