feat(validate): add command to validate JSON AST against Concerto met…#69
feat(validate): add command to validate JSON AST against Concerto met…#69hussein-saad wants to merge 6 commits intoaccordproject:mainfrom
Conversation
…amodel and enhance print function with AST validation Add validateAST method to validate Concerto metamodel JSON structures Enhance print function to validate AST structure before converting to CTO Provide detailed error messages for invalid AST structur Signed-off-by: Hussein Saad <hussein.saad2021@gmail.com>
|
hi @DianaLease, could you please review this PR? |
mttrbrts
left a comment
There was a problem hiding this comment.
Thanks for the contribution! Let's reuse the validation logic that already exists in the MetamodelUtil module, rather than redefining it partially here.
Signed-off-by: Hussein Saad <hussein.saad2021@gmail.com>
mttrbrts
left a comment
There was a problem hiding this comment.
Thanks for your contribution. Just a few small comments from me.
… AST validation Signed-off-by: Hussein Saad <hussein.saad2021@gmail.com>
Signed-off-by: Hussein Saad <hussein.saad2021@gmail.com>
Signed-off-by: Hussein Saad <hussein.saad2021@gmail.com>
|
hey @mttrbrts, could you take a look at the changes when you have time? |
There was a problem hiding this comment.
Pull request overview
Adds CLI support for validating Concerto JSON metamodel ASTs, and strengthens print by validating AST input before converting it to CTO, addressing #55.
Changes:
- Added a new
validate-astCLI command for validating a JSON AST against the Concerto metamodel. - Added
Commands.validateASTand integrated AST validation intoCommands.print. - Expanded test coverage for validation and error-handling scenarios.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
index.js |
Adds the new validate-ast CLI command and its argument parsing/handler logic. |
lib/commands.js |
Implements validateAST and validates JSON ASTs in print prior to printing. |
test/cli.js |
Adds unit tests for validateAST and new print error-handling cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| yargs.option('strict', { | ||
| describe: 'perform strict validation', | ||
| type: 'boolean', | ||
| default: true | ||
| }); |
There was a problem hiding this comment.
The strict option is defined for the validate-ast command but never used (it isn't passed to Commands.validateAST, and validateAST doesn't accept options). This is confusing for CLI users; either wire it through (e.g., add an options parameter) or remove the flag until it’s supported.
| yargs.option('strict', { | |
| describe: 'perform strict validation', | |
| type: 'boolean', | |
| default: true | |
| }); |
| Commands.validateAST(json); | ||
| } catch (err) { | ||
| Logger.error('Error validating AST'); |
There was a problem hiding this comment.
The validate-ast handler swallows the underlying exception details by always logging only "Error validating AST" and exiting. This makes it hard to diagnose whether the failure was due to file I/O, JSON parsing, or metamodel validation; log err.message (and/or the full error) and consider printing the success message returned by Commands.validateAST on success.
| Commands.validateAST(json); | |
| } catch (err) { | |
| Logger.error('Error validating AST'); | |
| const result = Commands.validateAST(json); | |
| if (result) { | |
| Logger.info(result); | |
| } | |
| } catch (err) { | |
| Logger.error('Error validating AST'); | |
| Logger.error(err && err.message ? err.message : err); |
| let json; | ||
| try { | ||
| json = JSON.parse(inputString); | ||
| // Validate the AST before printing | ||
| this.validateAST(json); | ||
| } catch (error) { | ||
| throw new Error(error.message); | ||
| } |
There was a problem hiding this comment.
print catches JSON/AST validation errors and rethrows new Error(error.message), which discards the original error type and stack trace. Prefer rethrowing the original error (or wrapping while preserving the original error as the cause) so callers and users can debug failures more easily.
| * Validates a Concerto JSON Abstract Syntax Tree (AST) | ||
| * | ||
| * @param {object} ast - The AST to validate | ||
| * @returns {string} Success message | ||
| * @throws {Error} If validation fails or file cannot be read/parsed. |
There was a problem hiding this comment.
The JSDoc for validateAST says it throws if the "file cannot be read/parsed", but this method only validates an already-parsed AST object and never reads/parses a file. Please update the docstring to match the actual behavior (or move file parsing responsibilities into this method if that’s the intent).
| * Validates a Concerto JSON Abstract Syntax Tree (AST) | |
| * | |
| * @param {object} ast - The AST to validate | |
| * @returns {string} Success message | |
| * @throws {Error} If validation fails or file cannot be read/parsed. | |
| * Validates a Concerto JSON Abstract Syntax Tree (AST). | |
| * | |
| * @param {object} ast - The AST to validate. | |
| * @returns {string} Success message. | |
| * @throws {Error} If validation fails. |
|
|
||
| try { | ||
| // deserialize the user's AST using the metamodel's rules. | ||
| // This will validates the structure, types, and constraints ($class, required fields etc.) |
There was a problem hiding this comment.
Minor grammar in the inline comment: "This will validates" should be "This will validate". Fixing this keeps comments clear and professional.
| // This will validates the structure, types, and constraints ($class, required fields etc.) | |
| // This will validate the structure, types, and constraints ($class, required fields etc.) |
| try { | ||
| await Commands.print('/path/to/nonexistent/file.json'); | ||
| expect.fail('Expected error was not thrown'); | ||
| } catch (err) { | ||
| err.should.be.an.instanceOf(Error); |
There was a problem hiding this comment.
This test uses a hard-coded POSIX path (/path/to/nonexistent/file.json) to trigger ENOENT. Since CI runs on Windows/macOS/Linux, it’s safer to generate a guaranteed-nonexistent path using tmp/os.tmpdir() + a random filename so the test is platform-independent and can’t accidentally exist.
| try { | |
| await Commands.print('/path/to/nonexistent/file.json'); | |
| expect.fail('Expected error was not thrown'); | |
| } catch (err) { | |
| err.should.be.an.instanceOf(Error); | |
| const tempDir = await tmp.dir({ unsafeCleanup: true }); | |
| const nonExistentPath = path.join(tempDir.path, `nonexistent-${Date.now()}.json`); | |
| try { | |
| try { | |
| await Commands.print(nonExistentPath); | |
| expect.fail('Expected error was not thrown'); | |
| } catch (err) { | |
| err.should.be.an.instanceOf(Error); | |
| } | |
| } finally { | |
| tempDir.cleanup(); |
|
@hussein-saad will you be able to address the comments? |
Closes #55
Changes
New Command Addition:
validate-astcommand to the CLI, which validates a JSON syntax tree against the Concerto metamodel.Error Handling Improvements:
printmethod to catch and report JSON parsing errors and invalid AST structures. (lib/commands.js)validateASTmethod. (lib/commands.js)Validation Enhancements:
validateASTmethod in theCommandsclass to validate a Concerto JSON AST. This method checks for the correct structure, required properties. (lib/commands.js)Test Coverage Expansion:
validateASTmethod to cover various scenarios, including valid and invalid models, missing properties, and error handling. (test/cli.js)test/cli.js)Related Issues
Author Checklist
--signoffoption of git commit.mainfromfork:branchname