suma 0.5.9 → 0.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +27 -0
- data/CLAUDE.md +17 -5
- data/README.adoc +101 -0
- data/lib/suma/anchor_validator.rb +85 -0
- data/lib/suma/artifact_server.rb +102 -0
- data/lib/suma/cli/artifact_server_cli.rb +22 -0
- data/lib/suma/cli/build.rb +4 -0
- data/lib/suma/cli/core.rb +50 -4
- data/lib/suma/cli/export.rb +1 -1
- data/lib/suma/cli/extract_terms.rb +1 -1
- data/lib/suma/cli/generate_register.rb +1 -1
- data/lib/suma/cli/ingest_translations.rb +36 -0
- data/lib/suma/cli/package_gcr.rb +51 -0
- data/lib/suma/cli/validate.rb +16 -0
- data/lib/suma/cli.rb +4 -1
- data/lib/suma/closure_validator.rb +124 -20
- data/lib/suma/corpus_graph.rb +79 -16
- data/lib/suma/gcr_package.rb +230 -0
- data/lib/suma/link_validation_result.rb +8 -0
- data/lib/suma/link_validator.rb +0 -3
- data/lib/suma/output_canonicalizer.rb +107 -0
- data/lib/suma/processor.rb +94 -20
- data/lib/suma/provenance.rb +92 -12
- data/lib/suma/schema_collection.rb +1 -0
- data/lib/suma/schema_compiler.rb +79 -13
- data/lib/suma/schema_manifest_generator.rb +10 -3
- data/lib/suma/schema_profile.rb +12 -0
- data/lib/suma/schema_template/anchors.rb +154 -0
- data/lib/suma/schema_template/document.rb +2 -93
- data/lib/suma/schema_template/plain.rb +10 -6
- data/lib/suma/schema_template.rb +1 -0
- data/lib/suma/site_build.rb +153 -0
- data/lib/suma/staged_collection_builder.rb +11 -3
- data/lib/suma/translation_ingester.rb +169 -0
- data/lib/suma/version.rb +1 -1
- data/lib/suma.rb +7 -0
- metadata +12 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 01e0b1dd212172912b654cac481e0ce1eea1efee1275f45d4332c0a6bbb28e69
|
|
4
|
+
data.tar.gz: 54399e492be26b0a09595debdc61c256f566da28ed13ca002cae2a6eb0925b57
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9fb0aebf85233af1df6162efb518605bd7ab01c7396e7af6012144fd05c74a135ba7d2833b7bb633fa45c755e067d6799569412df0b21458b33d2730a5081a3a
|
|
7
|
+
data.tar.gz: d9836497a01e7711aece5c76534ecfa4e7e0876bfd414aab783ada288b1906e07a3f3b6994d17085f294b79a827c16ecb61bab7cf305a823b9527933e5aa7f1c
|
data/.rubocop_todo.yml
CHANGED
|
@@ -116,9 +116,11 @@ Lint/UnusedMethodArgument:
|
|
|
116
116
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
117
117
|
Metrics/AbcSize:
|
|
118
118
|
Exclude:
|
|
119
|
+
- 'lib/suma/gcr_package.rb'
|
|
119
120
|
- 'bin/benchmark_corpus'
|
|
120
121
|
- 'lib/suma/worker_pool.rb'
|
|
121
122
|
- 'spec/suma/reproducibility_spec.rb'
|
|
123
|
+
- 'spec/suma/cli/build_integration_spec.rb'
|
|
122
124
|
- 'lib/suma/cli/resolve.rb'
|
|
123
125
|
- 'lib/suma/urn_resolver.rb'
|
|
124
126
|
- 'lib/suma/cli/check_svg_quality.rb'
|
|
@@ -155,6 +157,8 @@ Metrics/BlockLength:
|
|
|
155
157
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
156
158
|
Metrics/CyclomaticComplexity:
|
|
157
159
|
Exclude:
|
|
160
|
+
- 'lib/suma/gcr_package.rb'
|
|
161
|
+
- 'lib/suma/corpus_graph.rb'
|
|
158
162
|
- 'lib/suma/worker_pool.rb'
|
|
159
163
|
- 'lib/suma/urn_resolver.rb'
|
|
160
164
|
- 'lib/suma/cli/check_svg_quality.rb'
|
|
@@ -172,6 +176,8 @@ Metrics/CyclomaticComplexity:
|
|
|
172
176
|
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
173
177
|
Metrics/MethodLength:
|
|
174
178
|
Exclude:
|
|
179
|
+
- 'lib/suma/artifact_server.rb'
|
|
180
|
+
- 'lib/suma/gcr_package.rb'
|
|
175
181
|
- 'bin/benchmark_corpus'
|
|
176
182
|
- 'lib/suma/cli/build.rb'
|
|
177
183
|
- 'lib/suma/worker_pool.rb'
|
|
@@ -204,6 +210,7 @@ Metrics/MethodLength:
|
|
|
204
210
|
# Configuration parameters: Max, CountKeywordArgs, MaxOptionalParameters.
|
|
205
211
|
Metrics/ParameterLists:
|
|
206
212
|
Exclude:
|
|
213
|
+
- 'lib/suma/gcr_package.rb'
|
|
207
214
|
- 'lib/suma/processor.rb'
|
|
208
215
|
- 'lib/suma/express_schema.rb'
|
|
209
216
|
- 'lib/suma/term_extractor.rb'
|
|
@@ -216,6 +223,7 @@ Metrics/ParameterLists:
|
|
|
216
223
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
217
224
|
Metrics/PerceivedComplexity:
|
|
218
225
|
Exclude:
|
|
226
|
+
- 'lib/suma/gcr_package.rb'
|
|
219
227
|
- 'lib/suma/worker_pool.rb'
|
|
220
228
|
- 'lib/suma/eengine/wrapper.rb'
|
|
221
229
|
- 'lib/suma/jsdai/figure_image.rb'
|
|
@@ -259,6 +267,16 @@ RSpec/ContextWording:
|
|
|
259
267
|
# Configuration parameters: Max, CountAsOne.
|
|
260
268
|
RSpec/ExampleLength:
|
|
261
269
|
Exclude:
|
|
270
|
+
- 'spec/suma/site_build_spec.rb'
|
|
271
|
+
- 'spec/suma/output_canonicalizer_spec.rb'
|
|
272
|
+
- 'spec/suma/anchor_validator_spec.rb'
|
|
273
|
+
- 'spec/suma/translation_ingester_spec.rb'
|
|
274
|
+
- 'spec/suma/ifc_profile_pipeline_spec.rb'
|
|
275
|
+
- 'spec/suma/schema_manifest_generator_spec.rb'
|
|
276
|
+
- 'spec/suma/schema_naming_spec.rb'
|
|
277
|
+
- 'spec/suma/cli/build_integration_spec.rb'
|
|
278
|
+
- 'spec/suma/artifact_server_spec.rb'
|
|
279
|
+
- 'spec/suma/gcr_package_spec.rb'
|
|
262
280
|
- 'spec/suma/schema_cache_spec.rb'
|
|
263
281
|
- 'spec/suma/worker_pool_spec.rb'
|
|
264
282
|
- 'spec/suma/schema_collection_rebuild_targets_spec.rb'
|
|
@@ -338,6 +356,11 @@ RSpec/MessageSpies:
|
|
|
338
356
|
# Configuration parameters: Max.
|
|
339
357
|
RSpec/MultipleExpectations:
|
|
340
358
|
Exclude:
|
|
359
|
+
- 'spec/suma/site_build_spec.rb'
|
|
360
|
+
- 'spec/suma/output_canonicalizer_spec.rb'
|
|
361
|
+
- 'spec/suma/cli/build_integration_spec.rb'
|
|
362
|
+
- 'spec/suma/artifact_server_spec.rb'
|
|
363
|
+
- 'spec/suma/gcr_package_spec.rb'
|
|
341
364
|
- 'spec/suma/schema_cache_spec.rb'
|
|
342
365
|
- 'spec/suma/worker_pool_spec.rb'
|
|
343
366
|
- 'spec/suma/reproducibility_spec.rb'
|
|
@@ -400,11 +423,13 @@ RSpec/NestedGroups:
|
|
|
400
423
|
RSpec/DescribeClass:
|
|
401
424
|
Exclude:
|
|
402
425
|
- 'spec/suma/reproducibility_spec.rb'
|
|
426
|
+
- 'spec/suma/ifc_profile_pipeline_spec.rb'
|
|
403
427
|
|
|
404
428
|
RSpec/SpecFilePathFormat:
|
|
405
429
|
Exclude:
|
|
406
430
|
- '**/spec/routing/**/*'
|
|
407
431
|
- 'spec/suma/cli/expressir_spec.rb'
|
|
432
|
+
- 'spec/suma/ifc_profile_pipeline_spec.rb'
|
|
408
433
|
|
|
409
434
|
# Offense count: 1
|
|
410
435
|
RSpec/StubbedMock:
|
|
@@ -415,6 +440,8 @@ RSpec/StubbedMock:
|
|
|
415
440
|
# Configuration parameters: Max.
|
|
416
441
|
RSpec/MultipleMemoizedHelpers:
|
|
417
442
|
Exclude:
|
|
443
|
+
- 'spec/suma/ifc_profile_pipeline_spec.rb'
|
|
444
|
+
- 'spec/suma/gcr_package_spec.rb'
|
|
418
445
|
- 'spec/suma/provenance_spec.rb'
|
|
419
446
|
- 'spec/suma/worker_pool_spec.rb'
|
|
420
447
|
- 'spec/suma/schema_cache_spec.rb'
|
data/CLAUDE.md
CHANGED
|
@@ -37,11 +37,15 @@ exe/suma reformat PATH # Reformat EXP files (us
|
|
|
37
37
|
exe/suma generate-schemas METANORMA_YAML SCHEMAS_YAML # Generate schema manifest from site manifest
|
|
38
38
|
exe/suma extract-terms SCHEMA_YAML GLOSSARIST_DIR -u URN # Extract EXPRESS entity concepts to Glossarist v3 format
|
|
39
39
|
exe/suma extract-terms ... --edition 3 --language-codes fra deu # Provenance + linked localizations
|
|
40
|
+
exe/suma ingest-translations CONCEPTS_DIR TRANSLATIONS_FILE [-o OUT] # Overlay translated localized-concept content onto extracted concepts
|
|
40
41
|
exe/suma resolve URN --manifest SCHEMAS_YAML --concepts DIR --register register.yaml -o OUT # Emit canonical JSON + HTML
|
|
41
42
|
exe/suma resolve --all --manifest SCHEMAS_YAML --concepts DIR --register register.yaml -o OUT # Emit every URN artifact
|
|
43
|
+
exe/suma package-gcr CONCEPTS_DIR --register register.yaml --shortname ID --version V --title T --description D -o OUT # Package concepts into a .gcr archive
|
|
44
|
+
exe/suma serve ARTIFACTS_DIR --port 2113 # Serve resolved URN artifacts with Accept negotiation
|
|
42
45
|
exe/suma generate-register SCHEMA_YAML OUT_DIR -u URN --id ID --ref REF # Generate hierarchical register.yaml from schema manifest
|
|
43
46
|
exe/suma validate links SCHEMAS_FILE DOCS_PATH # Validate EXPRESS cross-reference links
|
|
44
47
|
exe/suma validate closure SCHEMAS_MANIFEST [DOCUMENTS_PATH] # Referential closure: every reference resolves (exit 1 on violations)
|
|
48
|
+
exe/suma validate anchors SCHEMA_DOCS_PATH # Rendered docs: every xref and in-page link resolves (exit 1 on dead links)
|
|
45
49
|
```
|
|
46
50
|
|
|
47
51
|
## Schema profiles
|
|
@@ -51,8 +55,10 @@ identifiers and paths map to types (`ExpressSchema::Type`), how
|
|
|
51
55
|
identifiers become display names (`SchemaNaming`), and the ordered
|
|
52
56
|
register categories (`SchemaCategory`). Registered profiles: `iso10303`
|
|
53
57
|
(default; STEP conventions incl. `/applications/` → application
|
|
54
|
-
protocol)
|
|
55
|
-
|
|
58
|
+
protocol), `generic` (no STEP conventions), and `ifc` (buildingSMART
|
|
59
|
+
IFC editions: standalone classification, `IFC4`-style edition names via
|
|
60
|
+
`/\Aifc\d+(x\d+)*\z/`). The CLI takes `--profile` on `export`,
|
|
61
|
+
`extract-terms`, and `generate-register`.
|
|
56
62
|
|
|
57
63
|
## ISO 10303 AP publications
|
|
58
64
|
|
|
@@ -81,10 +87,12 @@ per-publication parent section.
|
|
|
81
87
|
- **`SchemaCategory`** — value object mapping `ExpressSchema::Type` to a register/export category (id, label, prefix, types, directory). Single source of truth for category identity across `SchemaExporter`, `SchemaNaming`, and `RegisterManifestGenerator`
|
|
82
88
|
- **`Urn`** — value object encapsulating ISO URN semantics (wildcard stripping, base/alias split, leaf composition for `for_schema`/`for_term`/`for_entity`)
|
|
83
89
|
- **`TermExtractor`** — extracts EXPRESS entity concepts from a schema manifest into Glossarist v3 YAML format. Generates definitions with URN cross-references, processes remarks into notes, and resolves EXPRESS xrefs to URN mentions. Assigns stable UUIDv5 identifiers
|
|
90
|
+
- **`TranslationIngester`** — T5 translation ingestion: overlays a YAML sequence of localized-concept entries (keyed by `concept_id` or localized UUID) onto extracted concepts through the Glossarist/lutaml-model framework. Entry fields win; omitted fields keep the source-language content; a new language is created with the same UUIDv5 convention as the linked localizations, and the persisted localization "id" is preserved (Glossarist parses it as `#id`, not `#uuid`)
|
|
84
91
|
- **`RegisterManifestGenerator`** (file: `lib/suma/register_manifest_generator.rb`) — generates a Glossarist v3 `register.yaml` with hierarchical sections from a schema manifest. Classifies schemas via `ExpressSchema::Type` (DRY), delegates naming to `SchemaNaming` (OCP), orders resources before modules. Uses the Section model's `children` field for hierarchy
|
|
85
92
|
- **`SchemaNaming`** — pure module that converts EXPRESS schema IDs to human-readable display names. Strips type suffixes (`_schema`/`_arm`/`_mim`/`_bom`), title-cases with acronym preservation (AIC, AEC, BREP, 2D, 3D…), lowercases function words, appends type labels (ARM/MIM)
|
|
86
|
-
- **`SchemaTemplate::Plain` / `SchemaTemplate::Document`** — pure renderers for the AsciiDoc body fed to Metanorma (no I/O, no schema knowledge). `
|
|
87
|
-
- **`
|
|
93
|
+
- **`SchemaTemplate::Plain` / `SchemaTemplate::Document`** — pure renderers for the AsciiDoc body fed to Metanorma (no I/O, no schema knowledge). Both render the schema through `formatted_hyperlinked_adoc` (live cross-references) under the shared `Anchors` block, which emits one `[[id]]` per linkable element — schema-qualified ids plus bare `entity.attribute` pairs, matching Expressir's two xref forms. `Plain` produces HTML+XML for top-level schemas; `Document` produces XML-only for schemas-only entries. `validate anchors` verifies zero dead links in rendered docs
|
|
94
|
+
- **`AnchorValidator`** — T4 dead-link gate: for every rendered `doc_*.adoc` + `doc_*.html`, each `<<target,...>>` xref must have an anchor in the HTML (unresolved xrefs are silently dropped by the renderer) and every in-page `href="#..."` must hit an id; cross-document xrefs are out of scope. `validate anchors SCHEMA_DOCS_PATH` exits 1 on violations
|
|
95
|
+
- **`SchemaCompiler`** — orchestrates one schema's compilation: writes adoc + config, invokes `Metanorma::Compile`. Templates are injected via the constructor (composition over inheritance). A render key over adoc, config, schema source, and `Provenance.render_toolchain` is stored in `.suma-render-key` beside the outputs; an unchanged key with the requested outputs present reuses them without invoking Metanorma
|
|
88
96
|
- **`SchemaCollection`** — orchestrates processing of all schemas from a config; selects `Plain` for top-level schemas and `Document` for schemas-only entries
|
|
89
97
|
- **`SchemaExporter`** — standalone export of schemas from manifest or `.exp` files to a directory, with optional ZIP
|
|
90
98
|
- **`CollectionManifest`** — pure data model (lutaml-model attributes + YAML mappings) for one node of a Metanorma collection manifest. No imperative methods
|
|
@@ -97,9 +105,13 @@ per-publication parent section.
|
|
|
97
105
|
- **`OwlProjection`** — S2 formal semantics: projects a parsed corpus into OWL/Turtle. Entities → `owl:Class`; `SUBTYPE OF` → `rdfs:subClassOf`; SELECT → `owl:unionOf`; enums → `owl:oneOf` named individuals; simple type aliases → `rdfs:Datatype`; explicit/derived/inverse attributes → object/datatype properties attached through named `owl:Restriction` nodes (cardinality from optionality and aggregate bounds); WHERE rules and DERIVE/INVERSE clauses → annotated (`rdfs:comment`) constraints. IRIs come from `Urn` (`<base>:tech:<schema>.<element>`), per-schema ontologies declare `owl:imports` for their `USE FROM`/`REFERENCE` targets, and the corpus ontology imports every schema. `#validate` checks materialization, property declarations, orphan classes, and superclass acyclicity. Output contains no blank nodes, so projections are deterministic and golden-comparable
|
|
98
106
|
- **`SchemaCache`** — content-addressed on-disk store for generated `.exp` output and parsed Expressir repositories. Keys compose source bytes with the Expressir version (plus Suma/Marshal versions for parsed entries), so a hit is equivalent to a fresh build. Enabled by `SUMA_SCHEMA_CACHE_DIR`; hit/miss counters expose parse reuse. **`NullCache`** is the disabled-mode null object
|
|
99
107
|
- **`BuildPlan`** — incremental-build decision: hashes every schema source, diffs against the persisted state, and expands changed schemas to their transitive dependents through `CorpusGraph`. State defaults to `plain_schemas/.suma-build-state.json`; `SchemaCollection#rebuild_targets` is the build-facing query
|
|
108
|
+
- **`SiteBuild`** — T3 site freshness: keys every source file under the site root (excluding generated trees, render copies, and the Relaton cache) plus the render toolchain, records the key and produced files in `_site/.suma-site-build.json`, and lets `Processor` skip the collection render when nothing changed. Generated per-document artifacts (`document*.xml*`, `*_index.html`, `*.err.html`, `*.log.txt`, temp files) are never treated as inputs
|
|
109
|
+
- **`OutputCanonicalizer`** — T3 determinism: Metanorma assigns random UUIDs to manifest nodes without identifiers and stamps rendered documents with a random 8-letter root type. This pass rewrites those to position-derived UUIDv5s and a fixed marker in the emitted manifest and root XML, while preserving UUIDs that occur in source YAML, so identical builds are byte-identical
|
|
100
110
|
- **`WorkerPool`** — bounded worker pool for independent per-schema work. Schema export runs in the pool (`build --jobs N`); Metanorma document compilation stays sequential and composes with `StagedCollectionBuilder`'s process isolation
|
|
101
111
|
- **`UrnResolver`** — S4 dereferenceable identity: resolves `tech:` schema/element URNs from a manifest, `term:` concept URNs from Glossarist documents, and the dataset URN from `register.yaml`; emits canonical JSON plus a static HTML document per URN at a path derived from the URN itself. Every URN the register emits resolves against the artifact set
|
|
102
|
-
- **`
|
|
112
|
+
- **`ArtifactServer`** — T2 development server for the resolved artifact tree (`serve DIRECTORY`): dependency-free TCP responder negotiating JSON vs HTML by the Accept header at URN-derived paths; production hosting maps the same paths statically
|
|
113
|
+
- **`GcrPackage`** — T2 packaging (`package-gcr`): bundles extracted concepts into a GCR archive for the Glossarist Vocabulary Browser — `metadata.yaml` (identity, statistics, schema_version), `register.yaml`, and `concepts/` in the browser's canonical flat format (`termid`, `term`, `{lang}` blocks). Standard variant only; `created_at` is injectable for byte-reproducible archives
|
|
114
|
+
- **`Provenance`** — S5 build provenance: sha256 of every input and output (files or directory trees) plus Ruby/Expressir/Suma toolchain versions, written as canonical JSON by `build --provenance FILE`. `Provenance.verify` recomputes the digests independently and reports unrecorded files under the recorded output roots (`_site`, `schema_docs`, `plain_schemas`); explicit exclusions cover build metadata such as the site state file and staged store. `build --sign minisign|sigstore` (with `--sign-key` where needed) optionally signs the manifest, and `bin/release_provenance` signs keylessly with cosign in the release workflow (`SUMA_PROVENANCE_SIGN`). `Provenance.render_toolchain` keys rendered-document reuse
|
|
103
115
|
- **`LinkValidator`** — validates EXPRESS cross-reference links against a `SchemaIndex`; returns `LinkValidationResult` structs for unresolved links
|
|
104
116
|
|
|
105
117
|
### CLI structure
|
data/README.adoc
CHANGED
|
@@ -49,10 +49,13 @@ $ suma
|
|
|
49
49
|
suma convert-jsdai XML_FILE IMAGE_FILE OUTPUT_DIR # Convert JSDAI XML and image files to SVG and EXP
|
|
50
50
|
suma export *FILES -o OUTPUT # Export EXPRESS schemas or project them to OWL
|
|
51
51
|
suma extract-terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH # Extract entity concepts to Glossarist v3
|
|
52
|
+
suma ingest-translations CONCEPTS_DIR TRANSLATIONS_FILE [-o OUT] # Overlay translated content onto extracted concepts
|
|
52
53
|
suma generate-register SCHEMA_MANIFEST_FILE OUTPUT_PATH # Generate hierarchical register.yaml
|
|
53
54
|
suma generate-schemas METANORMA_MANIFEST_FILE SCHEMA_MANIFEST_FILE # Generate a schema manifest from a site manifest
|
|
54
55
|
suma reformat EXPRESS_FILE_PATH # Reformat EXPRESS files
|
|
55
56
|
suma resolve [URN] --manifest=MANIFEST -o OUTPUT # Emit canonical JSON + HTML for URNs
|
|
57
|
+
suma package-gcr CONCEPTS_DIR --register=REGISTER -o OUTPUT # Package concepts into a .gcr archive
|
|
58
|
+
suma serve DIRECTORY # Serve resolved artifacts (Accept negotiation)
|
|
56
59
|
suma validate SUBCOMMAND ...ARGS # Validate express documents
|
|
57
60
|
----
|
|
58
61
|
|
|
@@ -85,6 +88,20 @@ Options:
|
|
|
85
88
|
The generated `schemas-*.yaml` file name is derived from the input file name
|
|
86
89
|
with the word `metanorma` replaced with `schemas`.
|
|
87
90
|
|
|
91
|
+
Repeated builds reuse work and are reproducible: a schema document is rendered
|
|
92
|
+
again only when its adoc, schema config, schema source, or the rendering
|
|
93
|
+
toolchain changed, and the collection render is skipped entirely when no site
|
|
94
|
+
input changed (state: `_site/.suma-site-build.json`). Metanorma's random
|
|
95
|
+
manifest identifiers and per-document type markers are canonicalized, so two
|
|
96
|
+
identical builds produce byte-identical output. A provenance manifest covers
|
|
97
|
+
`schema_docs`, `plain_schemas`, and `_site`, and verification reports files
|
|
98
|
+
that appeared under those roots without being recorded (build metadata such as
|
|
99
|
+
the site state file is excluded explicitly).
|
|
100
|
+
|
|
101
|
+
Top-level schema documents render with live cross-reference links: every
|
|
102
|
+
`schema.entity` and `entity.attribute` reference Expressir emits becomes an
|
|
103
|
+
in-page link, and `suma validate anchors` verifies that no link is dead.
|
|
104
|
+
|
|
88
105
|
[example]
|
|
89
106
|
====
|
|
90
107
|
.To compile SRL subset test collection
|
|
@@ -210,6 +227,19 @@ $ suma validate closure SCHEMAS_MANIFEST [DOCUMENTS_PATH] [--format terminal|jso
|
|
|
210
227
|
When `DOCUMENTS_PATH` is given, documentation-layer link failures are merged
|
|
211
228
|
into the same report.
|
|
212
229
|
|
|
230
|
+
==== Anchors subcommand
|
|
231
|
+
|
|
232
|
+
The `anchors` subcommand checks rendered schema documents for dead links:
|
|
233
|
+
every Expressir cross-reference (`<<schema.entity,...>>`,
|
|
234
|
+
`<<entity.attribute,...>>`) emitted in a compiled `doc_*.adoc` must have a
|
|
235
|
+
matching anchor in its rendered `doc_*.html`, and every in-page `href` must
|
|
236
|
+
point at an existing id. It exits non-zero on violations.
|
|
237
|
+
|
|
238
|
+
[source,sh]
|
|
239
|
+
----
|
|
240
|
+
$ suma validate anchors SCHEMA_DOCS_PATH
|
|
241
|
+
----
|
|
242
|
+
|
|
213
243
|
|
|
214
244
|
=== Generate schemas command
|
|
215
245
|
|
|
@@ -337,6 +367,37 @@ $ bundle exec suma extract-terms schemas-activity-modules.yml terms_output
|
|
|
337
367
|
----
|
|
338
368
|
====
|
|
339
369
|
|
|
370
|
+
=== Ingest translations command
|
|
371
|
+
|
|
372
|
+
The `suma ingest-translations` command overlays translated content onto
|
|
373
|
+
extracted concepts. A translations file is a YAML sequence of
|
|
374
|
+
localized-concept documents, each keyed by concept id (or localized
|
|
375
|
+
UUID) and carrying the fields to apply:
|
|
376
|
+
|
|
377
|
+
[source,yaml]
|
|
378
|
+
----
|
|
379
|
+
- concept_id: example_schema.part
|
|
380
|
+
data:
|
|
381
|
+
language_code: fra
|
|
382
|
+
terms:
|
|
383
|
+
- designation: pièce
|
|
384
|
+
type: expression
|
|
385
|
+
normative_status: preferred
|
|
386
|
+
definition:
|
|
387
|
+
- content: "Composant d'un assemblage."
|
|
388
|
+
----
|
|
389
|
+
|
|
390
|
+
Every field the entry provides replaces that localization's field; every
|
|
391
|
+
field it omits keeps the source-language content (a language absent from
|
|
392
|
+
the extracted concepts is created with the same stable UUID convention
|
|
393
|
+
the linked localizations use). Updated concepts are written in place, or
|
|
394
|
+
to `--output` when given.
|
|
395
|
+
|
|
396
|
+
[source,sh]
|
|
397
|
+
----
|
|
398
|
+
$ suma ingest-translations CONCEPTS_DIR TRANSLATIONS_FILE [-o OUTPUT_DIR]
|
|
399
|
+
----
|
|
400
|
+
|
|
340
401
|
|
|
341
402
|
=== Generate register command
|
|
342
403
|
|
|
@@ -695,6 +756,7 @@ names, and the ordered register categories. Registered profiles:
|
|
|
695
756
|
|
|
696
757
|
`iso10303`:: Default; STEP conventions including `/applications/` classifying as an application protocol
|
|
697
758
|
`generic`:: No STEP conventions (one category for every schema)
|
|
759
|
+
`ifc`:: buildingSMART IFC editions: one standalone schema per edition (`ifc4`, `ifc4x3`, ...), edition names preserved uppercase (`IFC4`, `IFC4X3`), Ifc-prefixed declarations, one `Other Schemas` register category
|
|
698
760
|
|
|
699
761
|
An AP publication is a lead schema bundled with the module and resource
|
|
700
762
|
schemas it USEs. `--publication SCHEMA_ID` computes the transitive
|
|
@@ -727,6 +789,45 @@ $ suma export --format owl --corpus --urn urn:iso:std:iso:10303:-2:ed-2:en \
|
|
|
727
789
|
-o OUTPUT schemas.yaml
|
|
728
790
|
----
|
|
729
791
|
|
|
792
|
+
=== Package concepts for the Vocabulary Browser
|
|
793
|
+
|
|
794
|
+
The `package-gcr` command bundles extracted concepts into a GCR
|
|
795
|
+
(Glossarist Concept Repository) archive — the sealed distribution format
|
|
796
|
+
consumed by the Glossarist Vocabulary Browser:
|
|
797
|
+
|
|
798
|
+
[source,sh]
|
|
799
|
+
----
|
|
800
|
+
$ suma package-gcr CONCEPTS_DIR --register register.yaml \
|
|
801
|
+
--shortname my-dataset --version 1.0.0 \
|
|
802
|
+
--title "My Dataset" --description "Concepts from my corpus" \
|
|
803
|
+
-o OUT
|
|
804
|
+
----
|
|
805
|
+
|
|
806
|
+
The archive contains `metadata.yaml` (identity, statistics), the original
|
|
807
|
+
`register.yaml`, and `concepts/` in the browser's canonical flat format
|
|
808
|
+
(`termid`, `term`, one block per language). Both a versioned
|
|
809
|
+
(`{shortname}-{version}.gcr`) and an unversioned (`{shortname}.gcr`)
|
|
810
|
+
archive are written. Pass `--created-at` to pin the package timestamp for
|
|
811
|
+
byte-reproducible archives. Point the browser's `datasets.yml` at the
|
|
812
|
+
published archive (or at the concepts directory in development via
|
|
813
|
+
`localPath`).
|
|
814
|
+
|
|
815
|
+
=== Serve resolved artifacts
|
|
816
|
+
|
|
817
|
+
`suma serve` serves a `resolve --all` artifact tree at its URN-derived
|
|
818
|
+
paths, returning JSON or HTML according to the request's `Accept`
|
|
819
|
+
header:
|
|
820
|
+
|
|
821
|
+
[source,sh]
|
|
822
|
+
----
|
|
823
|
+
$ suma serve OUT --port 2113
|
|
824
|
+
$ curl -H "Accept: application/json" \
|
|
825
|
+
http://localhost:2113/urn/iso/std/iso/10303/-2/ed-2/en/tech/action_schema.action
|
|
826
|
+
----
|
|
827
|
+
|
|
828
|
+
Production hosting maps the same paths statically; no application server
|
|
829
|
+
is required.
|
|
830
|
+
|
|
730
831
|
=== Resolve URNs command
|
|
731
832
|
|
|
732
833
|
The `resolve` command turns URNs into static, dereferenceable artifacts: a
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Suma
|
|
4
|
+
# Validates that every cross-reference a rendered schema document emits
|
|
5
|
+
# resolves inside it. The Expressir hyperlinked source emits xref macros
|
|
6
|
+
# (`<<schema.entity,...>>`, `<<entity.attribute,...>>`); when a target is
|
|
7
|
+
# missing, the renderer silently drops the link, so the check is done on
|
|
8
|
+
# the source macros against the anchors present in the rendered HTML —
|
|
9
|
+
# plus the reverse check that every in-page href hits an existing id.
|
|
10
|
+
class AnchorValidator
|
|
11
|
+
XREF_PATTERN = /<<([^,>]+)(?:,[^>]*)?>>/
|
|
12
|
+
ID_PATTERN = /id="([^"]+)"/
|
|
13
|
+
FRAGMENT_PATTERN = /href="#([^"]+)"/
|
|
14
|
+
|
|
15
|
+
# @param directory [String] tree of compiled schema docs (doc_*.adoc
|
|
16
|
+
# with their rendered doc_*.html)
|
|
17
|
+
def initialize(directory)
|
|
18
|
+
@directory = directory
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Array<LinkValidationResult>] dead links (empty = valid)
|
|
22
|
+
def validate
|
|
23
|
+
Dir.glob(File.join(@directory, "**", "doc_*.adoc"))
|
|
24
|
+
.flat_map { |adoc| validate_document(adoc) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def validate_document(adoc)
|
|
30
|
+
html = adoc.sub(/\.adoc\z/, ".html")
|
|
31
|
+
return [missing_html(adoc, html)] unless File.file?(html)
|
|
32
|
+
|
|
33
|
+
content = File.read(adoc)
|
|
34
|
+
ids, fragments = rendered_digests(html)
|
|
35
|
+
|
|
36
|
+
xref_violations(adoc, content, ids, fragments) +
|
|
37
|
+
fragment_violations(html, ids)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def rendered_digests(html)
|
|
41
|
+
rendered = File.read(html)
|
|
42
|
+
[rendered.scan(ID_PATTERN).flatten.uniq,
|
|
43
|
+
rendered.scan(FRAGMENT_PATTERN).flatten.uniq]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def xref_violations(adoc, content, ids, fragments)
|
|
47
|
+
content.scan(XREF_PATTERN).flatten.uniq.filter_map do |target|
|
|
48
|
+
next if cross_document?(target) || resolved?(target, ids, fragments)
|
|
49
|
+
|
|
50
|
+
LinkValidationResult.new(
|
|
51
|
+
file: adoc, line: nil, link: target,
|
|
52
|
+
reason: "cross-reference has no anchor in the rendered document"
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def fragment_violations(html, ids)
|
|
58
|
+
File.read(html).scan(FRAGMENT_PATTERN).flatten.uniq.filter_map do |frag|
|
|
59
|
+
next if ids.include?(frag)
|
|
60
|
+
|
|
61
|
+
LinkValidationResult.new(
|
|
62
|
+
file: html, line: nil, link: "##{frag}",
|
|
63
|
+
reason: "in-page link points at no anchor in the document"
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Xrefs that cross documents (Asciidoctor `path.adoc#anchor` syntax)
|
|
69
|
+
# resolve against other pages and are out of scope here.
|
|
70
|
+
def cross_document?(target)
|
|
71
|
+
target.include?("/") || target.include?("#")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def resolved?(target, ids, fragments)
|
|
75
|
+
ids.include?(target) || fragments.include?(target)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def missing_html(adoc, html)
|
|
79
|
+
LinkValidationResult.new(
|
|
80
|
+
file: adoc, line: nil, link: html,
|
|
81
|
+
reason: "no rendered HTML next to the adoc source"
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "socket"
|
|
4
|
+
|
|
5
|
+
module Suma
|
|
6
|
+
# Development server for the emitted URN artifact tree: serves the
|
|
7
|
+
# static files at their URN-derived paths, negotiating JSON vs HTML by
|
|
8
|
+
# the Accept header. Production hosting maps the same paths statically.
|
|
9
|
+
class ArtifactServer
|
|
10
|
+
DEFAULT_PORT = 2113
|
|
11
|
+
|
|
12
|
+
attr_reader :directory, :port
|
|
13
|
+
|
|
14
|
+
# @param directory [String] the resolve output directory
|
|
15
|
+
# @param port [Integer] TCP port; 0 picks an ephemeral port
|
|
16
|
+
def initialize(directory, port: DEFAULT_PORT)
|
|
17
|
+
@directory = File.expand_path(directory)
|
|
18
|
+
@port = port
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Resolve one HTTP request to a response.
|
|
22
|
+
#
|
|
23
|
+
# @param path [String] request path (with or without extension)
|
|
24
|
+
# @param accept [String, nil] Accept header value
|
|
25
|
+
# @return [Array(String, String, String)] status, content type, body
|
|
26
|
+
def call(path, accept = nil)
|
|
27
|
+
clean = path.to_s.split("?").first.to_s
|
|
28
|
+
return not_found if clean.include?("..")
|
|
29
|
+
|
|
30
|
+
clean = "/index.html" if clean.empty? || clean == "/"
|
|
31
|
+
file = artifact_file(clean, accept)
|
|
32
|
+
return not_found unless file
|
|
33
|
+
|
|
34
|
+
["200", content_type(file), File.read(file, encoding: "utf-8")]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Handle a single connection (one HTTP request).
|
|
38
|
+
def serve(socket)
|
|
39
|
+
request = socket.gets&.strip
|
|
40
|
+
return unless request
|
|
41
|
+
|
|
42
|
+
accept = read_headers(socket)["accept"]
|
|
43
|
+
status, type, body = call(request.split[1].to_s, accept)
|
|
44
|
+
socket.write(
|
|
45
|
+
"HTTP/1.1 #{status} #{status_name(status)}\r\n" \
|
|
46
|
+
"Content-Type: #{type}\r\nContent-Length: #{body.bytesize}\r\n" \
|
|
47
|
+
"Connection: close\r\n\r\n#{body}",
|
|
48
|
+
)
|
|
49
|
+
ensure
|
|
50
|
+
socket&.close
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Accept connections until interrupted.
|
|
54
|
+
def start
|
|
55
|
+
server = TCPServer.new("localhost", @port)
|
|
56
|
+
@port = server.addr[1]
|
|
57
|
+
Utils.log "Serving #{@directory} at http://localhost:#{@port}"
|
|
58
|
+
loop { serve(server.accept) }
|
|
59
|
+
ensure
|
|
60
|
+
server&.close
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def read_headers(socket)
|
|
66
|
+
headers = {}
|
|
67
|
+
while (line = socket.gets) && line != "\r\n" && !line.strip.empty?
|
|
68
|
+
key, value = line.split(":", 2)
|
|
69
|
+
headers[key.strip.downcase] = value.strip if value
|
|
70
|
+
end
|
|
71
|
+
headers
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def artifact_file(clean, accept)
|
|
75
|
+
base = clean.delete_prefix("/")
|
|
76
|
+
candidates = if base.end_with?(".json", ".html")
|
|
77
|
+
[base]
|
|
78
|
+
else
|
|
79
|
+
wants_json = accept.to_s.include?("application/json")
|
|
80
|
+
["#{base}.#{wants_json ? 'json' : 'html'}"]
|
|
81
|
+
end
|
|
82
|
+
candidates.map { |candidate| File.join(@directory, candidate) }
|
|
83
|
+
.find { |file| File.file?(file) }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def content_type(file)
|
|
87
|
+
if file.end_with?(".json")
|
|
88
|
+
"application/json"
|
|
89
|
+
else
|
|
90
|
+
"text/html; charset=utf-8"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def not_found
|
|
95
|
+
["404", "text/plain", "not found\n"]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def status_name(status)
|
|
99
|
+
status == "200" ? "OK" : "Not Found"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "thor"
|
|
4
|
+
|
|
5
|
+
module Suma
|
|
6
|
+
module Cli
|
|
7
|
+
# Serve the emitted URN artifact tree with Accept negotiation.
|
|
8
|
+
class ArtifactServerCli < Thor
|
|
9
|
+
def self.exit_on_failure?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc "serve DIRECTORY", "Serve resolved URN artifacts locally"
|
|
14
|
+
option :port, type: :numeric, default: ArtifactServer::DEFAULT_PORT,
|
|
15
|
+
desc: "TCP port to listen on"
|
|
16
|
+
def serve(directory)
|
|
17
|
+
Utils.log "Ctrl-C stops the server."
|
|
18
|
+
ArtifactServer.new(directory, port: options[:port]).start
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/suma/cli/build.rb
CHANGED
|
@@ -33,6 +33,9 @@ module Suma
|
|
|
33
33
|
option :sign_key, type: :string,
|
|
34
34
|
desc: "Signing key (minisign requires it; sigstore " \
|
|
35
35
|
"signs keylessly when omitted)"
|
|
36
|
+
option :no_valid, type: :boolean, default: false,
|
|
37
|
+
desc: "Skip Metanorma document validation " \
|
|
38
|
+
"(equivalent of metanorma --no-valid)"
|
|
36
39
|
|
|
37
40
|
def build(metanorma_site_manifest)
|
|
38
41
|
unless File.exist?(metanorma_site_manifest)
|
|
@@ -62,6 +65,7 @@ module Suma
|
|
|
62
65
|
provenance_file: options[:provenance],
|
|
63
66
|
sign_method: options[:sign],
|
|
64
67
|
sign_key: options[:sign_key],
|
|
68
|
+
no_valid: options[:no_valid],
|
|
65
69
|
).run
|
|
66
70
|
end
|
|
67
71
|
|
data/lib/suma/cli/core.rb
CHANGED
|
@@ -42,6 +42,8 @@ module Suma
|
|
|
42
42
|
desc: "Sign the provenance manifest: minisign or sigstore"
|
|
43
43
|
option :sign_key, type: :string,
|
|
44
44
|
desc: "Signing key (sigstore signs keylessly when omitted)"
|
|
45
|
+
option :no_valid, type: :boolean, default: false,
|
|
46
|
+
desc: "Skip Metanorma document validation"
|
|
45
47
|
def build(_site_manifest)
|
|
46
48
|
Cli::Build.start
|
|
47
49
|
end
|
|
@@ -70,6 +72,8 @@ module Suma
|
|
|
70
72
|
desc: "Owning edition recorded on each concept"
|
|
71
73
|
option :language_codes, type: :array,
|
|
72
74
|
desc: "Additional linked localization languages"
|
|
75
|
+
option :profile, type: :string, default: "iso10303",
|
|
76
|
+
desc: "Corpus profile (iso10303, generic, or ifc)"
|
|
73
77
|
def extract_terms(schema_manifest_file, glossarist_output_path)
|
|
74
78
|
TermExtractor.new(
|
|
75
79
|
schema_manifest_file,
|
|
@@ -78,6 +82,7 @@ module Suma
|
|
|
78
82
|
language_code: options[:language_code],
|
|
79
83
|
edition: options[:edition],
|
|
80
84
|
language_codes: options[:language_codes],
|
|
85
|
+
profile: options[:profile],
|
|
81
86
|
).call
|
|
82
87
|
end
|
|
83
88
|
|
|
@@ -94,7 +99,7 @@ module Suma
|
|
|
94
99
|
option :owner, type: :string, default: Suma::RegisterManifestGenerator::DEFAULT_OWNER,
|
|
95
100
|
desc: "Owner of the dataset (e.g. 'ISO/TC 184/SC 4')"
|
|
96
101
|
option :profile, type: :string, default: "iso10303",
|
|
97
|
-
desc: "Corpus profile (iso10303 or
|
|
102
|
+
desc: "Corpus profile (iso10303, generic, or ifc)"
|
|
98
103
|
option :year, type: :numeric,
|
|
99
104
|
desc: "Edition year for the register"
|
|
100
105
|
option :supersedes, type: :string,
|
|
@@ -141,7 +146,7 @@ module Suma
|
|
|
141
146
|
"USE-FROM/REFERENCE closure (manifest " \
|
|
142
147
|
"input only)"
|
|
143
148
|
option :profile, type: :string, default: "iso10303",
|
|
144
|
-
desc: "Corpus profile (iso10303 or
|
|
149
|
+
desc: "Corpus profile (iso10303, generic, or ifc)"
|
|
145
150
|
option :format, type: :string, default: "express", banner: "FORMAT",
|
|
146
151
|
desc: "Output format: express (default) or owl"
|
|
147
152
|
option :corpus, type: :boolean, default: false,
|
|
@@ -164,8 +169,7 @@ module Suma
|
|
|
164
169
|
desc "validate SUBCOMMAND ...ARGS", "Validate express documents"
|
|
165
170
|
subcommand "validate", Cli::Validate
|
|
166
171
|
|
|
167
|
-
desc "resolve [URN]", "Resolve URNs to canonical JSON + HTML artifacts"
|
|
168
|
-
# Mirrors so Core accepts the switches Cli::Resolve reparses; the
|
|
172
|
+
desc "resolve [URN]", "Resolve URNs to canonical JSON + HTML artifacts" # Mirrors so Core accepts the switches Cli::Resolve reparses; the
|
|
169
173
|
# inner class owns their declarations.
|
|
170
174
|
option :manifest, type: :string, required: true,
|
|
171
175
|
desc: "Schema manifest used for schema/entity URNs"
|
|
@@ -183,6 +187,48 @@ module Suma
|
|
|
183
187
|
Cli::Resolve.start
|
|
184
188
|
end
|
|
185
189
|
|
|
190
|
+
desc "package-gcr CONCEPTS_DIR",
|
|
191
|
+
"Package extracted concepts into a .gcr archive"
|
|
192
|
+
# Mirrors so Core accepts the switches Cli::PackageGcr reparses; the
|
|
193
|
+
# inner class owns their declarations.
|
|
194
|
+
option :register, type: :string, required: true,
|
|
195
|
+
desc: "register.yaml (dataset identity)"
|
|
196
|
+
option :shortname, type: :string, required: true,
|
|
197
|
+
desc: "Dataset id"
|
|
198
|
+
option :version, type: :string, required: true,
|
|
199
|
+
desc: "Semver of this dataset release"
|
|
200
|
+
option :title, type: :string, required: true,
|
|
201
|
+
desc: "Human-readable dataset title"
|
|
202
|
+
option :description, type: :string, required: true,
|
|
203
|
+
desc: "Dataset description"
|
|
204
|
+
option :created_at, type: :string,
|
|
205
|
+
desc: "Package timestamp (pin for reproducibility)"
|
|
206
|
+
option :output, type: :string, aliases: "-o", required: true,
|
|
207
|
+
desc: "Output directory for the .gcr archives"
|
|
208
|
+
def package_gcr(_concepts_dir)
|
|
209
|
+
Cli::PackageGcr.start
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
desc "ingest-translations CONCEPTS_DIR TRANSLATIONS_FILE",
|
|
213
|
+
"Overlay translated localized-concept content onto extracted " \
|
|
214
|
+
"Glossarist concepts"
|
|
215
|
+
# Mirrors so Core accepts the switches Cli::IngestTranslations
|
|
216
|
+
# reparses; the inner class owns their declarations.
|
|
217
|
+
option :output, type: :string, aliases: "-o",
|
|
218
|
+
desc: "Write updated concepts here (default: " \
|
|
219
|
+
"update CONCEPTS_DIR in place)"
|
|
220
|
+
def ingest_translations(_concepts_dir, _translations_file)
|
|
221
|
+
Cli::IngestTranslations.start
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
desc "serve DIRECTORY", "Serve resolved URN artifacts locally"
|
|
225
|
+
option :port, type: :numeric,
|
|
226
|
+
default: Suma::ArtifactServer::DEFAULT_PORT,
|
|
227
|
+
desc: "TCP port to listen on"
|
|
228
|
+
def serve(_directory)
|
|
229
|
+
Cli::ArtifactServerCli.start
|
|
230
|
+
end
|
|
231
|
+
|
|
186
232
|
desc "check_svg_quality [PATH]",
|
|
187
233
|
"Check SVG quality and sort by severity (critical files first)"
|
|
188
234
|
option :pattern, type: :string, default: Cli::CheckSvgQuality::DEFAULT_PATTERN,
|
data/lib/suma/cli/export.rb
CHANGED
|
@@ -35,7 +35,7 @@ module Suma
|
|
|
35
35
|
"USE-FROM/REFERENCE closure (manifest " \
|
|
36
36
|
"input only)"
|
|
37
37
|
option :profile, type: :string, default: "iso10303",
|
|
38
|
-
desc: "Corpus profile (iso10303 or
|
|
38
|
+
desc: "Corpus profile (iso10303, generic, or ifc)"
|
|
39
39
|
option :format, type: :string, default: "express", banner: "FORMAT",
|
|
40
40
|
desc: "Output format: express (default) or owl"
|
|
41
41
|
option :corpus, type: :boolean, default: false,
|