diff --git a/README.md b/README.md index 3b924198..389d5d1e 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,9 @@ from Cucumber. The protocol aims to decouple various components of the Cucumber ![messages.png](jsonschema/messages.png) -Note: Markdown and Excel formats are currently not supported and mentioned here as potential future alternative languages to express BDD scenarios. +Notes: + * The image sketches out the general concept, but is incomplete. See [relations.md](jsonschema/relations.md) for a complete visualisation of the relationships between messages. + * Markdown and Excel formats are currently not supported and mentioned here as potential future alternative languages to express BDD scenarios. ## JSON Schema diff --git a/codegen/templates/relations.md.erb b/codegen/templates/relations.md.erb new file mode 100644 index 00000000..791342f1 --- /dev/null +++ b/codegen/templates/relations.md.erb @@ -0,0 +1,56 @@ +# Cucumber Messages + +All relationships where an entity is referenced by `id`. + +Notes: + * The left side cardinality of the relationship is always rendered as one-or-more, but may also be exactly-one. This can't be extracted from the json schema easily. + * Worker is not actually an entity in the message protocol, but is referenced by id. + * `AstNode` is not actually an entity in the message protocol, but does reference an element in the `GherkinDocument`. + +```mermaid +--- +title: Entity relationships - by id +config: + layout: elk +--- +erDiagram +<%- @schemas.each do |key, schema| -%> +<%- schema['properties'].each do |property_name, property| -%> +<%- if property_name.end_with?("Id") + referent = property_name.delete_suffix("Id") + referent[0] = referent[0].upcase + required = (schema['required'] || []).index(property_name) +-%> +<%= class_name(key) %> }|..<%= required ? '||' : 'o|' %> <%= referent %>: <%= property_name %> +<%- end -%> +<%- +if property_name.end_with?("Ids") + referent = property_name.delete_suffix("Ids") + referent[0] = referent[0].upcase + required = (schema['required'] || []).index(property_name) +-%> +<%= class_name(key) %> }|..<%= required ? '|{' : 'o{' %> <%= referent %>: <%= property_name %> +<%- end -%> +<%- end -%> +<%- end -%> +``` + +And all has-a relationships, excluding `Envelope`: + +```mermaid +--- +title: Entity relationships - has a +config: + layout: elk +--- +erDiagram +<% @schemas.each do |key, schema| -%> +<%- schema['properties'].each do |property_name, property| -%> +<%- + next unless property['$ref'] + next unless class_name(key) != "Envelope" +-%> +<%= class_name(key) %> ||..|| <%= class_name(property['$ref']) %>: has a +<%- end -%> +<%- end -%> +``` diff --git a/jsonschema/Makefile b/jsonschema/Makefile index 90a166c4..a8cb259e 100644 --- a/jsonschema/Makefile +++ b/jsonschema/Makefile @@ -32,7 +32,7 @@ schemas = \ help: ## Show this help @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \n\nWhere is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) -generate: require-doc messages.md ## Generate markdown documentation using the scripts in ./jsonschema/scripts for the generation +generate: require-doc messages.md relations.md ## Generate markdown documentation using the scripts in ./jsonschema/scripts for the generation validate: $(schemas) ## Validate the json schemas are valid npm install @@ -46,5 +46,8 @@ messages.md: $(schemas) ../codegen/codegen.rb ../codegen/templates/markdown.md.e ruby ../codegen/codegen.rb Generator::Markdown markdown.md.erb > $@ ruby ../codegen/codegen.rb Generator::Markdown markdown.enum.md.erb >> $@ +relations.md: $(schemas) ../codegen/codegen.rb ../codegen/templates/relations.md.erb + ruby ../codegen/codegen.rb Generator::Markdown relations.md.erb > $@ + clean: ## Remove automatically generated documentation files and related artifacts - rm -f messages.md + rm -f messages.md relations.md diff --git a/jsonschema/relations.md b/jsonschema/relations.md new file mode 100644 index 00000000..84a2aaa0 --- /dev/null +++ b/jsonschema/relations.md @@ -0,0 +1,105 @@ +# Cucumber Messages + +All relationships where an entity is referenced by `id`. + +Notes: + * The left side cardinality of the relationship is always rendered as one-or-more, but may also be exactly-one. This can't be extracted from the json schema easily. + * Worker is not actually an entity in the message protocol, but is referenced by id. + * `AstNode` is not actually an entity in the message protocol, but does reference an element in the `GherkinDocument`. + +```mermaid +--- +title: Entity relationships - by id +config: + layout: elk +--- +erDiagram +Attachment }|..o| TestCaseStarted: testCaseStartedId +Attachment }|..o| TestStep: testStepId +Attachment }|..o| TestRunStarted: testRunStartedId +Attachment }|..o| TestRunHookStarted: testRunHookStartedId +Pickle }|..|{ AstNode: astNodeIds +PickleStep }|..|{ AstNode: astNodeIds +PickleTag }|..|| AstNode: astNodeId +TestCase }|..|| Pickle: pickleId +TestCase }|..o| TestRunStarted: testRunStartedId +TestStep }|..o| Hook: hookId +TestStep }|..o| PickleStep: pickleStepId +TestStep }|..o{ StepDefinition: stepDefinitionIds +TestCaseFinished }|..|| TestCaseStarted: testCaseStartedId +TestCaseStarted }|..|| TestCase: testCaseId +TestCaseStarted }|..o| Worker: workerId +TestRunFinished }|..o| TestRunStarted: testRunStartedId +TestRunHookFinished }|..|| TestRunHookStarted: testRunHookStartedId +TestRunHookStarted }|..|| TestRunStarted: testRunStartedId +TestRunHookStarted }|..|| Hook: hookId +TestStepFinished }|..|| TestCaseStarted: testCaseStartedId +TestStepFinished }|..|| TestStep: testStepId +TestStepStarted }|..|| TestCaseStarted: testCaseStartedId +TestStepStarted }|..|| TestStep: testStepId +``` + +And all has-a relationships, excluding `Envelope`: + +```mermaid +--- +title: Entity relationships - has a +config: + layout: elk +--- +erDiagram +Attachment ||..|| Source: has a +Attachment ||..|| Timestamp: has a +GherkinDocument ||..|| Feature: has a +Background ||..|| Location: has a +Comment ||..|| Location: has a +DataTable ||..|| Location: has a +DocString ||..|| Location: has a +Examples ||..|| Location: has a +Examples ||..|| TableRow: has a +Feature ||..|| Location: has a +FeatureChild ||..|| Rule: has a +FeatureChild ||..|| Background: has a +FeatureChild ||..|| Scenario: has a +Rule ||..|| Location: has a +RuleChild ||..|| Background: has a +RuleChild ||..|| Scenario: has a +Scenario ||..|| Location: has a +Step ||..|| Location: has a +Step ||..|| DocString: has a +Step ||..|| DataTable: has a +TableCell ||..|| Location: has a +TableRow ||..|| Location: has a +Tag ||..|| Location: has a +Hook ||..|| SourceReference: has a +Meta ||..|| Product: has a +Meta ||..|| Product: has a +Meta ||..|| Product: has a +Meta ||..|| Product: has a +Meta ||..|| Ci: has a +Ci ||..|| Git: has a +ParameterType ||..|| SourceReference: has a +ParseError ||..|| SourceReference: has a +PickleStep ||..|| PickleStepArgument: has a +PickleStepArgument ||..|| PickleDocString: has a +PickleStepArgument ||..|| PickleTable: has a +SourceReference ||..|| JavaMethod: has a +SourceReference ||..|| JavaStackTraceElement: has a +SourceReference ||..|| Location: has a +StepDefinition ||..|| StepDefinitionPattern: has a +StepDefinition ||..|| SourceReference: has a +StepMatchArgument ||..|| Group: has a +TestCaseFinished ||..|| Timestamp: has a +TestCaseStarted ||..|| Timestamp: has a +TestRunFinished ||..|| Timestamp: has a +TestRunFinished ||..|| Exception: has a +TestRunHookFinished ||..|| TestStepResult: has a +TestRunHookFinished ||..|| Timestamp: has a +TestRunHookStarted ||..|| Timestamp: has a +TestRunStarted ||..|| Timestamp: has a +TestStepFinished ||..|| TestStepResult: has a +TestStepFinished ||..|| Timestamp: has a +TestStepResult ||..|| Duration: has a +TestStepResult ||..|| Exception: has a +TestStepStarted ||..|| Timestamp: has a +```