Skip to content
Merged
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
2 changes: 1 addition & 1 deletion changes/unreleased/asciidoc-document-bodies.added.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- Document prose can be written as AsciiDoc: a KerML textual representation `rep language "asciidoc" /* … */` inside a `Document` or `Section` expands in place into content blocks, and one inside a `part : Paragraph` yields that paragraph, alongside the Markdown form. Paragraphs, admonitions (a strong lead label), bullet and numbered lists, tables of text cells under a header row (static `Table` blocks with `cols` widths), `[stem]` blocks (`Formula`) and block images (`Image`) map onto the existing content kinds; `_emphasis_`, `*strong*`, `` `monospaced` ``, `stem:[…]`, `link:`, URLs, `<<xref>>` and the new `sysml:ref[<target>]` inline macro map onto runs, the reference forms resolved as `Ref::target` is. The body is parsed by Asciidoctor.js run as an external converter — `scripts/asciidoc/asciidoctor-json.js`, provisioned by `scripts/download-doc-pdf-toolchain.sh` and named by `OPENSYSML_ASCIIDOCTOR` — and a missing or failing converter is a typed planning error (`document-plan-markup-tool-missing`, `document-plan-markup-tool-failed`) naming the script and the variable. Constructs no content block renders, `sysml:value[…]` among them, are refused with `document-plan-unsupported-markup-construct` naming the construct and its body line.
- Document prose can be written as AsciiDoc: a KerML textual representation `rep language "asciidoc" /* … */` inside a `Document` or `Section` expands in place into content blocks, and one inside a `part : Paragraph` yields that paragraph, alongside the Markdown form. Paragraphs, admonitions (a strong lead label), bullet and numbered lists, tables of text cells under a header row (static `Table` blocks with `cols` widths), `[stem]` blocks (`Formula`) and block images (`Image`) map onto the existing content kinds; `_emphasis_`, `*strong*`, `` `monospaced` ``, `stem:[…]`, `link:`, URLs, `<<xref>>` and the new `sysml:ref[<target>]` inline macro map onto runs, the reference forms resolved as `Ref::target` is. The body is parsed by Asciidoctor.js run as an external converter — `scripts/asciidoc/asciidoctor-json.js`, provisioned by `scripts/download-doc-pdf-toolchain.sh` and named by `OPENSYSML_ASCIIDOCTOR` — and a failing converter is a typed planning error (`document-plan-markup-tool-failed`), a missing one a validation warning (`document-plan-markup-tool-missing`), each naming the script and the variable. Constructs no content block renders, `sysml:value[…]` among them, are refused with `document-plan-unsupported-markup-construct` naming the construct and its body line.
1 change: 1 addition & 0 deletions changes/unreleased/markup-tool-missing-warning.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- `sysml -validate` no longer fails over a model whose `rep language "asciidoc"` bodies need a converter the host lacks: a missing markup converter is now the warning `document-plan-markup-tool-missing` at the document's first such body, naming the converter looked for, whether `OPENSYSML_ASCIIDOCTOR` named it or it was the default looked up on `PATH`, and the remedy, and the rest of the document is still validated with those bodies unchecked (`-warnings-as-errors` makes it a failure). A converter that is found but fails stays the error `document-plan-markup-tool-failed`, and rendering a document still fails when its converter is missing, since the rendering needs the body. A document reported on its converter being missing or failing writes no interface record, so installing the converter is seen on the next run rather than hidden by a cached verdict.
87 changes: 87 additions & 0 deletions cmd/sysml/markup_tool_missing_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package main

import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/Open-MBEE/OpenSysML/internal/ir/docplan/markup"
)

const (
selfModelDir = "../../examples/self-model"
markupToolMissingCode = "document-plan-markup-tool-missing"
markupToolMissingAdvice = "the AsciiDoc converter asciidoctor-json was not found on PATH (" + markup.AsciiDocEnv + " is unset); run ./scripts/download-doc-pdf-toolchain.sh and point " + markup.AsciiDocEnv + " at build/doc-pdf/asciidoctor/asciidoctor-json.js"
)

// hostEnv is the environment of a host whose AsciiDoc converter is converter
// — none when empty: the variable unset and nothing on PATH — with a record
// cache of its own, so no verdict of another host's run is held.
func hostEnv(t *testing.T, converter string) []string {
t.Helper()
env := []string{markup.AsciiDocEnv + "=" + converter, "XDG_CACHE_HOME=" + t.TempDir()}
if converter == "" {
env = append(env, "PATH="+t.TempDir())
}
return env
}

func selfModelFiles(t *testing.T) []string {
t.Helper()
var files []string
for _, pattern := range []string{"*.sysml", "asciidoc/*.sysml"} {
matches, err := filepath.Glob(filepath.Join(selfModelDir, pattern))
if err != nil || len(matches) == 0 {
t.Fatalf("glob %s: %v, %d files", pattern, err, len(matches))
}
files = append(files, matches...)
}
return files
}

// TestValidateWithoutMarkupConverterWarns checks that a model whose prose
// needs a converter the host lacks still validates: one warning names the
// converter, where it was looked for and the remedy, and the exit status is
// 0 unless -warnings-as-errors asks otherwise; a rendering, which needs the
// body, fails.
func TestValidateWithoutMarkupConverterWarns(t *testing.T) {
binary := buildCLI(t)

result := runSysml(t, binary, hostEnv(t, ""), "-validate", selfModelDir)
wantReport(t, result, 0, "warning["+markupToolMissingCode+"]", "carries 3 asciidoc bodies that were not checked", markupToolMissingAdvice, "no errors")
if got := strings.Count(result.output(), "warning["); got != 1 {
t.Errorf("%d warnings, want exactly one:\n%s", got, result.output())
}

result = runSysml(t, binary, hostEnv(t, ""), "-validate", "-warnings-as-errors", selfModelDir)
wantReport(t, result, 2, "warning["+markupToolMissingCode+"]", "-warnings-as-errors")

result = runSysml(t, binary, hostEnv(t, ""), "-validate", "-format", "sarif", selfModelDir)
if result.status != 0 || !strings.Contains(result.stdout, `"level": "warning"`) || !strings.Contains(result.stdout, markupToolMissingCode) {
t.Errorf("-format sarif exited %d without the warning:\n%s", result.status, result.output())
}

args := append(selfModelFiles(t), "-render-document", "OpenSysMLAsciiDoc::MarkupNote")
result = runSysml(t, binary, hostEnv(t, ""), args...)
wantReport(t, result, 2, "carries a asciidoc body that could not be parsed: "+markupToolMissingAdvice)
}

// TestValidateWithMarkupConverterChecksBodies runs with the converter the
// environment names, as the PDF toolchain job does, and wants the bodies
// checked: no warning. Without one it skips, unless the job requires it.
func TestValidateWithMarkupConverterChecksBodies(t *testing.T) {
converter := os.Getenv(markup.AsciiDocEnv)
if converter == "" {
if required := os.Getenv("OPENSYSML_REQUIRE_PDF_TOOLCHAIN"); required != "" {
t.Fatalf("OPENSYSML_REQUIRE_PDF_TOOLCHAIN=%s but %s is unset", required, markup.AsciiDocEnv)
}
t.Skipf("%s is unset", markup.AsciiDocEnv)
}
binary := buildCLI(t)
result := runSysml(t, binary, hostEnv(t, converter), "-validate", "-warnings-as-errors", selfModelDir)
wantReport(t, result, 0, "no errors")
if strings.Contains(result.output(), markupToolMissingCode) {
t.Errorf("the converter %s was found, yet a body went unchecked:\n%s", converter, result.output())
}
}
9 changes: 9 additions & 0 deletions docs/internals/interface-records.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ whose `baseType` is bound conditionally. In the four OMG corpora one document of
(`kerml-examples/Simple Tests/MetadataTest.kerml`, a conditional `baseType`
binding). A refusal is never silent: the error names the fact and the element.

The workspace also refuses what a document plan in another document reads of
this one and no record answers (`plannedElsewhereLocked`): a document query
definition, whose result expression the plan evaluates from the tree, and a
`rep language "asciidoc"` body, which an external converter checks, so that
its verdict — the body checked, or the converter missing
(`document-plan-markup-tool-missing`) or failing — is the host's and would not
hold on another. Such a document is analyzed again wherever it is next
opened, and installing the converter is seen at once.

## Cache key

`Cache.InterfaceKey(name, content, libraryIdentity, mode)` is the document's
Expand Down
13 changes: 10 additions & 3 deletions docs/manual/authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -404,9 +404,16 @@ the content blocks of this chapter. `./scripts/download-doc-pdf-toolchain.sh`
installs the pinned Asciidoctor.js beside the script under
`build/doc-pdf/asciidoctor/`; point `OPENSYSML_ASCIIDOCTOR` at the installed
`asciidoctor-json.js` (an `asciidoctor-json` on `PATH` is found without it).
A document with an AsciiDoc body and no converter fails to plan with a typed
error naming the script and the variable, and a converter that fails is
reported with its message — the body is never rendered as literal text.
Validation (`sysml -validate`, the editors, the SARIF report) does not need
the converter installed: a document with an AsciiDoc body and no converter
gets one `document-plan-markup-tool-missing` warning at its first body, naming
the converter looked for, where (`OPENSYSML_ASCIIDOCTOR` or `PATH`) and the
remedy, and its AsciiDoc bodies go unchecked while the rest of the document
is still validated; `-warnings-as-errors` makes that a failure. A rendering
needs the body parsed, so `-render-document` fails with the same message
until the converter is installed, and a converter that is found but fails is
an error reported with its message — the body is never rendered as literal
text.

| AsciiDoc | Content |
| --- | --- |
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2145,7 +2145,7 @@ Specification: Model-defined rule; the predicate is a KerML constraint evaluated

A document definition (one typed by `DocumentDefinitions::Document` or a specialization of it) is compiled into a document plan before it is rendered; the member code names the rule that failed — a content with no title, an attribute that is not one string literal, a nested document, a query the document does not declare, a diagram kind no rendering supports — and the message states where. Correct the member the message names; the plain `document-plan` code reports a failure no rule classifies, with the planner's own message.

Emitted as `document-plan-<rule>`, one code per rule: `document-plan-invalid-context`, `document-plan-library-unavailable`, `document-plan-not-document-definition`, `document-plan-missing-title`, `document-plan-invalid-attribute`, `document-plan-invalid-content`, `document-plan-nested-document`, `document-plan-missing-text`, `document-plan-conflicting-text`, `document-plan-missing-query`, `document-plan-conflicting-query`, `document-plan-unknown-query`, `document-plan-query-planning`, `document-plan-invalid-style`, `document-plan-unknown-parameter`, `document-plan-duplicate-binding`, `document-plan-missing-binding`, `document-plan-unsupported-binding`, `document-plan-binding-type`, `document-plan-binding-multiplicity`, `document-plan-missing-view-source`, `document-plan-invalid-view-source`, `document-plan-unknown-view-source`, `document-plan-missing-diagram-kind`, `document-plan-conflicting-diagram-kind`, `document-plan-unsupported-diagram-kind`, `document-plan-invalid-direction`, `document-plan-unsupported-direction`, `document-plan-invalid-palette`, `document-plan-unsupported-palette`, `document-plan-invalid-ports`, `document-plan-unsupported-ports`, `document-plan-invalid-show`, `document-plan-invalid-overlay`, `document-plan-unsupported-overlay`, `document-plan-conflicting-runs`, `document-plan-ambiguous-run`, `document-plan-missing-run-text`, `document-plan-invalid-run-style`, `document-plan-missing-link-target`, `document-plan-missing-ref-target`, `document-plan-unknown-ref-target`, `document-plan-invalid-ref-target`, `document-plan-ambiguous-ref-target`, `document-plan-unknown-value-target`, `document-plan-invalid-value-target`, `document-plan-unknown-group-column`, `document-plan-invalid-column-widths`, `document-plan-invalid-column-labels`, `document-plan-column-run-without-query`, `document-plan-conflicting-column-runs`, `document-plan-missing-run-column`, `document-plan-conflicting-run-style`, `document-plan-unknown-run-column`, `document-plan-missing-definition-column`, `document-plan-unknown-definition-column`, `document-plan-missing-formula-source`, `document-plan-missing-image-location`, `document-plan-unsupported-markup-language`, `document-plan-unsupported-markup-construct`, `document-plan-misplaced-markup-body`, `document-plan-markup-body-not-paragraph`, `document-plan-markup-tool-missing`, `document-plan-markup-tool-failed`, `document-plan-markup-heading-level`.
Emitted as `document-plan-<rule>`, one code per rule: `document-plan-invalid-context`, `document-plan-library-unavailable`, `document-plan-not-document-definition`, `document-plan-missing-title`, `document-plan-invalid-attribute`, `document-plan-invalid-content`, `document-plan-nested-document`, `document-plan-missing-text`, `document-plan-conflicting-text`, `document-plan-missing-query`, `document-plan-conflicting-query`, `document-plan-unknown-query`, `document-plan-query-planning`, `document-plan-invalid-style`, `document-plan-unknown-parameter`, `document-plan-duplicate-binding`, `document-plan-missing-binding`, `document-plan-unsupported-binding`, `document-plan-binding-type`, `document-plan-binding-multiplicity`, `document-plan-missing-view-source`, `document-plan-invalid-view-source`, `document-plan-unknown-view-source`, `document-plan-missing-diagram-kind`, `document-plan-conflicting-diagram-kind`, `document-plan-unsupported-diagram-kind`, `document-plan-invalid-direction`, `document-plan-unsupported-direction`, `document-plan-invalid-palette`, `document-plan-unsupported-palette`, `document-plan-invalid-ports`, `document-plan-unsupported-ports`, `document-plan-invalid-show`, `document-plan-invalid-overlay`, `document-plan-unsupported-overlay`, `document-plan-conflicting-runs`, `document-plan-ambiguous-run`, `document-plan-missing-run-text`, `document-plan-invalid-run-style`, `document-plan-missing-link-target`, `document-plan-missing-ref-target`, `document-plan-unknown-ref-target`, `document-plan-invalid-ref-target`, `document-plan-ambiguous-ref-target`, `document-plan-unknown-value-target`, `document-plan-invalid-value-target`, `document-plan-unknown-group-column`, `document-plan-invalid-column-widths`, `document-plan-invalid-column-labels`, `document-plan-column-run-without-query`, `document-plan-conflicting-column-runs`, `document-plan-missing-run-column`, `document-plan-conflicting-run-style`, `document-plan-unknown-run-column`, `document-plan-missing-definition-column`, `document-plan-unknown-definition-column`, `document-plan-missing-formula-source`, `document-plan-missing-image-location`, `document-plan-unsupported-markup-language`, `document-plan-unsupported-markup-construct`, `document-plan-misplaced-markup-body`, `document-plan-markup-body-not-paragraph`, `document-plan-markup-tool-missing` (a warning), `document-plan-markup-tool-failed`, `document-plan-markup-heading-level`.

Specification: OpenSysML DocumentDefinitions library

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ run that would never finish into a reported error instead of a hang.
| `OPENSYSML_GRPC_MAX_HELD_OBJECTS` | `10000` | The most objects `sysml-grpc` keeps for one cached model, nested objects counted: `Instantiate` creates them and document queries bind and enumerate them for as long as the model stays cached. An `Instantiate`, query or render whose objects would pass the bound fails whole with `RESOURCE_EXHAUSTED`, leaving none of them, until the model leaves the cache, which releases them together; nothing is evicted behind an id a client holds. Read at startup |
| `OPENSYSML_WEASYPRINT`, `OPENSYSML_PANDOC`, `OPENSYSML_PRINCE` | unset (look on `PATH`) | Executable of the HTML-to-PDF converter `-render-document -doc-form pdf` drives under `-pdf-engine weasyprint` (the default; `pandoc` also needs it), `pandoc` or `prince`; the selected one absent is a typed `tool-missing` error naming its variable |
| `OPENSYSML_MMDC`, `OPENSYSML_MMDC_PUPPETEER` | unset (look for `mmdc` on `PATH`) | Mermaid CLI, which draws a PDF's Mermaid diagrams, and a Puppeteer configuration file for its browser (`--no-sandbox` in a container). Required as soon as a PDF has a Mermaid diagram; a document without one needs neither |
| `OPENSYSML_ASCIIDOCTOR` | unset (look for `asciidoctor-json` on `PATH`) | The AsciiDoc converter that parses `rep language "asciidoc"` prose bodies in generated documents: `scripts/asciidoc/asciidoctor-json.js` with Asciidoctor.js installed beside it, as `scripts/download-doc-pdf-toolchain.sh` provisions under `build/doc-pdf/asciidoctor/`. Without it, a document with an AsciiDoc body fails to plan naming the script and this variable. |
| `OPENSYSML_ASCIIDOCTOR` | unset (look for `asciidoctor-json` on `PATH`) | The AsciiDoc converter that parses `rep language "asciidoc"` prose bodies in generated documents: `scripts/asciidoc/asciidoctor-json.js` with Asciidoctor.js installed beside it, as `scripts/download-doc-pdf-toolchain.sh` provisions under `build/doc-pdf/asciidoctor/`. Without it, validating a document with an AsciiDoc body warns (`document-plan-markup-tool-missing`, a failure under `-warnings-as-errors`) that the bodies went unchecked, naming the converter, where it was looked for and this variable, and rendering the document fails with the same message. |
| `OPENSYSML_KATEX`, `OPENSYSML_KATEX_CSS` | unset (look for `katex` on `PATH`, its stylesheet beside it) | KaTeX, which typesets a PDF's formulas, and its stylesheet when it is not installed beside the command. Required as soon as a PDF has a formula |
| `OPENSYSML_DOT` | unset (look for `dot` on `PATH`) | Graphviz, which draws a PDF's diagrams under `-diagram-form dot` — `-Tsvg`, under the engine each block's `// layout:` header names (`dot`, `neato`, `neato -n`), so positioned views are drawn where the model put them. Optional: without it every DOT block stays in the PDF as source under a notice naming this variable |
| `OPENSYSML_PLANTUML_JAR`, `OPENSYSML_JAVA` | unset; unset (look for `java` on `PATH`) | The PlantUML jar that draws a PDF's diagrams under `-diagram-form plantuml` (`java -jar <jar> -tsvg -pipe`) and the Java that runs it. Optional: without the jar or a Java every PlantUML block stays in the PDF as source under a notice naming the variable to set. `go test ./internal/ir/view` also passes its PlantUML goldens through the jar's `-checkonly` when the jar is named |
Expand Down
3 changes: 2 additions & 1 deletion examples/self-model/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ not.

`-doc-form html` and `-doc-form asciidoc` render the same note as HTML and back to AsciiDoc.
Without the converter the command fails to plan the document with an error naming
`OPENSYSML_ASCIIDOCTOR` and the download script, and nothing is rendered as literal text. The
`OPENSYSML_ASCIIDOCTOR` and the download script, and nothing is rendered as literal text;
`-validate` over the model instead warns once that the note's bodies went unchecked. The
note's test, `TestSelfModelAsciiDocNoteRendersInstalled` in
[`../self_model_asciidoc_test.go`](../self_model_asciidoc_test.go), renders all three forms and
pins every value run against the model; it skips with the same instruction when the converter is
Expand Down
3 changes: 3 additions & 0 deletions internal/check/codes/catalogue.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func Catalogue() string {
b.WriteString(", ")
}
fmt.Fprintf(&b, "`%s-%s`", e.Code, k)
if severity := e.MemberSeverity(k); severity != e.Severity {
fmt.Fprintf(&b, " (a %s)", severity)
}
}
b.WriteString(".\n")
}
Expand Down
Loading
Loading