@peter.prib/renderengine 0.2.7 → 0.2.11

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.
Files changed (46) hide show
  1. package/README.md +66 -9
  2. package/REFERENCE.md +129 -0
  3. package/dist/renderengine-workspace.umd.js +5068 -2892
  4. package/dist/renderengine.umd.js +4874 -2888
  5. package/examples/data-model.html +40 -18
  6. package/package.json +1 -1
  7. package/src/charting/FormDialog.js +398 -385
  8. package/src/charting/RowsField.js +127 -0
  9. package/src/charting/datamodel/ClassificationLens.js +33 -0
  10. package/src/charting/datamodel/ClassificationScheme.js +98 -0
  11. package/src/charting/datamodel/DataModel.js +220 -4
  12. package/src/charting/datamodel/DataModelChecker.js +244 -2
  13. package/src/charting/datamodel/DataModelContext.js +40 -10
  14. package/src/charting/datamodel/DataModelEditCommand.js +47 -0
  15. package/src/charting/datamodel/DataModelPerspective.js +12 -2
  16. package/src/charting/datamodel/EnumerationType.js +64 -51
  17. package/src/charting/datamodel/LevelSchema.js +23 -0
  18. package/src/charting/datamodel/ServiceDomain.js +9 -0
  19. package/src/charting/datamodel/SqlDdl.js +85 -0
  20. package/src/charting/datamodel/SqlDdlFileFormat.js +23 -0
  21. package/src/charting/datamodel/index.js +21 -15
  22. package/src/charting/datamodel/naming/CamelCaseStyle.js +13 -0
  23. package/src/charting/datamodel/naming/LowerWordsStyle.js +13 -0
  24. package/src/charting/datamodel/naming/NameStyle.js +57 -0
  25. package/src/charting/datamodel/naming/NamingStandard.js +132 -0
  26. package/src/charting/datamodel/naming/PascalCaseStyle.js +13 -0
  27. package/src/charting/datamodel/naming/SnakeCaseStyle.js +13 -0
  28. package/src/charting/datamodel/naming/TitleCaseStyle.js +25 -0
  29. package/src/charting/datamodel/naming/UpperSnakeStyle.js +13 -0
  30. package/src/charting/datamodel/naming/index.js +8 -0
  31. package/src/charting/datamodel/scorecard/CompletenessCategory.js +30 -0
  32. package/src/charting/datamodel/scorecard/ConsistencyCategory.js +33 -0
  33. package/src/charting/datamodel/scorecard/DefinitionsCategory.js +33 -0
  34. package/src/charting/datamodel/scorecard/ModelScorecard.js +113 -0
  35. package/src/charting/datamodel/scorecard/ReadabilityCategory.js +37 -0
  36. package/src/charting/datamodel/scorecard/ScorecardCategory.js +46 -0
  37. package/src/charting/datamodel/scorecard/StandardsCategory.js +29 -0
  38. package/src/charting/datamodel/scorecard/StructureCategory.js +32 -0
  39. package/src/charting/datamodel/scorecard/index.js +8 -0
  40. package/src/charting/diagrams/DataModelDiagram.js +4 -11
  41. package/src/charting/diagrams/DataModelRelationshipStrategy.js +7 -1
  42. package/src/charting/diagrams/NodeGeometry.js +6 -2
  43. package/src/charting/toolbar/ToolbarSelect.js +6 -0
  44. package/src/datamodel.js +402 -4
  45. package/src/index.js +2666 -2666
  46. package/src/workspace/parts/DataModelPart.js +197 -6
package/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  # RenderEngine
2
2
 
3
- **An ArchiMate modeller, a diagram editor and a chart library that run in any browser tab, with no install and no
4
- runtime dependencies.**
3
+ **An ArchiMate modeller, a data modeller, a diagram editor and a chart library that run in any browser tab, with
4
+ no install and no runtime dependencies.**
5
5
 
6
6
  Open an Archi model, edit it the way you would in Archi, and save it back to the same `.archimate` file, without
7
- installing anything. Or put the same editor in your own app: it's a JavaScript library and a set of workbench parts,
8
- not a desktop application.
7
+ installing anything. Model data at three levels, governed and checked the way DAMA-DMBOK2 has it, with banking at
8
+ BIAN level built in. Or put the same editors in your own app: it's a JavaScript library and a set of workbench
9
+ parts, not a desktop application.
9
10
 
10
11
  ![The ArchiMate modeller: a layered view of an online shop, the model tree by layer with each type's picture, and the palette](https://gitlab.com/peter.prib/renderengine/-/raw/master/docs/images/archimate-modeller.png)
11
12
 
@@ -18,7 +19,7 @@ git clone https://gitlab.com/peter.prib/renderengine.git
18
19
  cd renderengine
19
20
  npm start # the ArchiMate modeller
20
21
  npm run diagram # the diagram editor (flowcharts, UML and more)
21
- npm run datamodel # a data model at each level, in each notation
22
+ npm run datamodel # the data modeller: an enterprise ontology and a retail bank at BIAN level
22
23
  ```
23
24
 
24
25
  No server is needed, and nothing needs installing first, because the built bundles are in `dist/`. You can also
@@ -26,7 +27,7 @@ open the pages directly:
26
27
 
27
28
  - `examples/archimate.html`: the ArchiMate modeller
28
29
  - `examples/diagram-editor.html`: the diagram editor
29
- - `examples/data-model.html`: a data model (conceptual, logical, physical; Chen, Crow's Foot, UML)
30
+ - `examples/data-model.html`: the data modeller
30
31
 
31
32
  All work in current Chrome, Edge, Firefox and Safari. Save writes back to the file you opened in Chrome and Edge;
32
33
  other browsers download the file instead.
@@ -111,6 +112,61 @@ It runs in the browser and embeds in other apps. It also has:
111
112
 
112
113
  ---
113
114
 
115
+ ## The data modeller
116
+
117
+ One model at the conceptual, logical and physical levels, read by each stakeholder in their own terms, governed and
118
+ checked the way DAMA-DMBOK2 has a model reviewed, and ready for banking at BIAN level. It shares the modeller's
119
+ workbench: several models open at once, undo for everything, files saved back where they came from, models kept in
120
+ the browser and backed up.
121
+
122
+ ![The data modeller: a retail bank's logical model through its Sensitive data lens, each entity coloured by how sensitive its data is](https://gitlab.com/peter.prib/renderengine/-/raw/master/docs/images/data-model.png)
123
+
124
+ ### One model, three levels
125
+
126
+ - **Concepts, logical entities and tables, each a schema of its own**, mapped any number either way: a concept
127
+ realised by several entities, several entities kept in one table. The **mapping view** draws the three side by
128
+ side, and **lineage** shows, for anything, what it realises and what realises it, all the way up and down.
129
+ - **Perspectives and contexts**: each stakeholder's names for the concepts, and what they mean in a context, with
130
+ its rules and where and when it applies, drawn as notes.
131
+ - **Chen, Crow's Foot and UML**, switched with one choice; **subtypes** (complete or not, disjoint or overlapping);
132
+ **data types and enumerations** defined once, code sets with their source and version, each linked to its
133
+ **ISO 20022** type.
134
+ - **Edit it on the diagram**: double-click an entity for its attribute table (keys, required, what a foreign key
135
+ references, classification), right-click for new and delete. Every edit is one undo step.
136
+
137
+ ### Banking at BIAN level
138
+
139
+ - **Service domains** with their control records, behaviour qualifiers and the service operations BIAN names for
140
+ them, and the **service landscape**: every service domain in its business area and domain.
141
+ - **Read BIAN's own published material instead of retyping it.** A BIAN semantic API (all 258 of release 14 read,
142
+ plain or with ISO 20022) becomes a control record, its qualifiers, their data types and ISO 20022 types in one
143
+ step. BIAN's service landscape in ArchiMate becomes service domains in their areas and domains: run over BIAN's
144
+ v14 model, every one it places lands in the right place.
145
+ - BIAN's vocabulary, its functional patterns, artifacts, action terms and qualifier types, is as BIAN's v14 model
146
+ has it.
147
+
148
+ ### Governed and checked (DAMA-DMBOK2)
149
+
150
+ - **Stewardship**: a business owner, data steward and technical custodian on each entity.
151
+ - **Classification**: sensitivity levels and categories (PII, PCI...) on entities and attributes, **checked down
152
+ the mappings**, so a table is never classified lower than the data it holds; a **lens** colours the model by it.
153
+ - **Check model** reviews it as DMBOK2 would: missing keys, foreign keys without relationships, repeating groups,
154
+ unresolved many-to-many, one name with two types, concepts without definitions, names against the **naming
155
+ standard** you set, **data quality rules** by dimension (completeness, validity, uniqueness...), and BIAN's one
156
+ owner per business object.
157
+ - **The Data Model Scorecard**: Steve Hoberman's ten categories, six measured from the model and four for a
158
+ reviewer, weighted as you choose, in one total.
159
+
160
+ ### To the database and the warehouse
161
+
162
+ - **SQL DDL**: the physical level as `CREATE TABLE`s with keys, foreign keys and comments.
163
+ - **A dimensional scheme**: facts at their grain with additive, semi-additive or non-additive measures, dimensions
164
+ with their history type and conformed across facts, a **star schema** view, and checks as Kimball would make
165
+ them.
166
+ - **Bases** to start a model from, and **compare and merge** between models.
167
+
168
+ ---
169
+
114
170
  ## The diagram editor
115
171
 
116
172
  The ArchiMate modeller is built on a general diagram editor, and every editing feature above is part of that
@@ -181,9 +237,10 @@ page:
181
237
  </script>
182
238
  ```
183
239
 
184
- Use `editorType: 'diagram-editor'` with `DiagramEditorPart` for the diagram editor. The model is a plain JavaScript
185
- API (`ArchimateModel`, `DiagramModel`), so you can also build, check, search, report on and export models with no
186
- UI at all.
240
+ Use `editorType: 'diagram-editor'` with `DiagramEditorPart` for the diagram editor, and `editorType: 'data-model'`
241
+ with `DataModelPart` for the data modeller. The models are plain JavaScript APIs (`ArchimateModel`, `DiagramModel`,
242
+ `DataModel`), so you can also build, check, score, search, report on and export models with no UI at all, under
243
+ Node too: `new DataModel(spec).checker().run()`, `new SqlDdl().write(model)`.
187
244
 
188
245
  ---
189
246
 
package/REFERENCE.md CHANGED
@@ -811,6 +811,109 @@ types — see `ARCHITECTURE.md`):
811
811
  one, or a qualifier, that is no logical entity, or with a pattern BIAN lacks, and a mapping joining an entity that
812
812
  is not there. Model ▸ **Check model…** lists the findings in the `ModelCheckDialog` the diagram editors' check uses;
813
813
  choosing one shows it (the entity's level, the service domain seen through, the mapping view).
814
+
815
+ **Checked as DMBOK2 reviews a model.** The check also finds, at the logical and physical levels: an entity with
816
+ attributes and no primary key (`no-primary-key`); a foreign key whose `references` (an entity, or `entity.attribute`,
817
+ by id or name) is not there (`reference-missing`) or has no relationship with its entity either way
818
+ (`foreign-key-without-relationship`), one saying nothing on an entity with no relationship (`foreign-key-unrelated`);
819
+ attributes differing only by a number at the end, a repeating group (`repeating-group`); one name with different
820
+ types at a level, in any case (`type-conflict`); and at the physical level a many-to-many relationship, which a table
821
+ between resolves (`many-to-many`). A concept without a definition (`definition-missing`) and anything defined only
822
+ by its name (`definition-restates-name`) are reported too. A model may keep a **naming standard**
823
+ (`model.namingStandard`, a `NamingStandard`; none by default): per level, for its entities and attributes, a
824
+ `style` (a `NameStyle`: Title Case, lower case words, snake_case, UPPER_SNAKE_CASE, camelCase, PascalCase; each
825
+ says whether a name is written so and suggests it), `classWords` an attribute name must end with, a `maxLength`,
826
+ and `abbreviations` a name must use (`{ number: 'num' }`); names that break it are reported (`naming`), with how
827
+ they would be written. Model ▸ **Naming standard** ▸ sets it (`NamingStandard.fields`), starts from
828
+ `NamingStandard.CONVENTIONAL` or removes it, one undo step each (`model.namingStandardCommand(spec|null)`).
829
+
830
+ ```javascript
831
+ new NamingStandard(NamingStandard.CONVENTIONAL).check('physical', 'attributes', 'account_number');
832
+ // ['has "number" where the standard writes "num"']
833
+ ```
834
+
835
+ **Stewardship, classification, lineage.** Any entity may say who answers for it (`stewardship: { owner, steward,
836
+ custodian }`: business owner, data steward, technical custodian) and how it is classified (`sensitivity`, a level of
837
+ the model's scheme, and `categories`); so may an attribute (its row's Sensitivity and Categories). The entity dialog
838
+ has both, its attribute table the attributes'. A model keeps a `ClassificationScheme` (`model.classificationScheme`:
839
+ sensitivity `levels` in order, lowest first, each with a colour, and `categories`; the default Public, Internal,
840
+ Confidential, Restricted and PII, PCI, PHI, Financial, saved only when changed; Model ▸ **Classification scheme…**).
841
+ An entity's effective classification (`scheme.effective(entity)`) is the highest of its own and its attributes', with
842
+ all their categories. The check reports what realises a classified entity, down the mappings, classified lower or
843
+ without its categories (`classification-lost`), and a sensitivity the scheme lacks (`classification-unknown`). A
844
+ **classification lens** (a perspective kind, `ClassificationLens`; Model ▸ New classification lens…) colours each
845
+ entity by its effective sensitivity, unclassified grey. `model.lineage(level, id)` gives what an entity realises
846
+ (`up`, to its concepts) and what realises it (`down`, to its tables), through the mappings; on hover an entity
847
+ shows its stewardship, classification and lineage (*realises*, *realised by*). Right-click an entity ▸ **Show
848
+ lineage** opens the mapping view with its lineage as it is and the rest greyed; there, right-click another for its
849
+ lineage, or the canvas ▸ Show all. The banking base classifies its party data and has a *Sensitive data* lens.
850
+
851
+ **Subtypes.** A relationship's `kind` says what it is (`RelationshipKind`, registered as perspective kinds are): an
852
+ association (`AssociationKind`, the default: a cardinality at each end, Chen's diamond) or a generalization
853
+ (`GeneralizationKind`, `kind: 'generalization'`: the source a subtype of the target, `complete` and `disjoint`
854
+ said on it). Each kind draws its own edge (`DataModelDiagram.buildEdge`): a generalization in every notation as a
855
+ line to its supertype ending in a hollow triangle, labelled `{complete, disjoint}` (in Chen, `ISA {…}`, a line,
856
+ not a diamond), with no cardinalities. The relationship dialog has the kind and a generalization's constraints.
857
+ The check reports generalizations that go round (`generalization-cycle`) and takes none for many-to-many. The
858
+ ontology's logical Party is the supertype of Person and Organisation.
859
+
860
+ **Data quality rules.** A context's rule may say which data quality dimension it measures (`dimension`, one of
861
+ `DataModelContext.QUALITY_DIMENSIONS`: Completeness, Validity, Uniqueness, Timeliness, Accuracy, Consistency) and
862
+ which attribute of what realises its concepts it is on (`attribute`); it then reads *Completeness of legal name:
863
+ always given* in its note and on hover (`DataModelContext.ruleText`). A context's dialog edits its rules as a table
864
+ (the rule, its concepts by name, its dimension, its attribute). The check reports a rule on an attribute nothing
865
+ realising its concepts has (`rule-attribute-missing`; names compared as words, so *tax number* is `tax_number`)
866
+ and a dimension DMBOK2 does not name (`quality-dimension-unknown`).
867
+
868
+ **Code sets.** An enumeration, as reference data, may say where it comes from (`source`), who keeps it (`owner`) and
869
+ which version it is (`version`): in its dialog, saved, and on hover in the data types view (`codeSet`).
870
+
871
+ **SQL DDL.** Export ▸ **SQL DDL (physical level)** writes the physical level as SQL (`SqlDdl`, `SqlDdlFileFormat`, an
872
+ export-only `ModelFileFormat`): a `CREATE TABLE` per table, its columns' types (`defaultType` where one has none)
873
+ and `NOT NULL` for required and key columns, its `PRIMARY KEY` and `UNIQUE` columns; a `FOREIGN KEY` per column
874
+ that references another table (`references`: a table, by id or name, meaning its primary key, or `table.column`),
875
+ a comment where one cannot be made; `COMMENT ON`s for definitions (`comments: false` leaves them out). Names SQL
876
+ would not take bare are quoted. ANSI SQL as PostgreSQL reads it.
877
+
878
+ A table's name may be schema-qualified (`sales.customer`, as a database lists its tables): the DDL names it in its
879
+ schema (`sales.customer`, each part quoted as it needs, `SqlDdl.tableName()`), and a reference to it is
880
+ `sales.customer` or `sales.customer.id`. The check and the DDL read a reference the one way,
881
+ `LevelSchema.resolveReference(ref)`: the whole text as a table (by id or name, any case), else what is before its
882
+ last dot as the table and the rest as its column — `{ entity, column }`, or null.
883
+
884
+ **A dimensional scheme.** At the logical and physical levels an entity may have a role (`EntityRole`, registered as
885
+ relationship kinds are): a **fact** (`FactRole`, `role: 'fact'`: what is measured, at a stated `grain`, its
886
+ attributes' `measure` additive, semi-additive or non-additive) or a **dimension** (`DimensionRole`: its `scdType`,
887
+ 0 to 3, how it keeps history, `conformed` when facts share it). The entity dialog has the role and what that role
888
+ has; the attribute table a Measure column. Level ▸ **Star schemas** (offered once there is a fact; `DataModel.STAR`,
889
+ `model.starView()`) draws, at the physical level if it has a fact (else the logical), each fact in a row of stars
890
+ with the dimensions it is related to around it, a shared dimension once, by the first, in their roles' colours. The
891
+ check reports a fact without its grain (`fact-no-grain`), related to no dimension (`fact-no-dimension`) or with no
892
+ measure (`fact-no-measure`), a measure on what is no fact (`measure-outside-fact`), and two facts joined directly
893
+ (`fact-to-fact`). The banking base has a daily balance star (`fact_daily_balance`, `dim_account` of type 2,
894
+ a conformed `dim_date`).
895
+
896
+ **The Data Model Scorecard.** Model ▸ **Scorecard…** scores the model on the ten categories of Steve Hoberman's Data
897
+ Model Scorecard (`ModelScorecard`, `model.scored()`), the total in its title. Six are measured from the model, a
898
+ `MeasuredCategory` each, with notes on why: **Completeness** (the share, averaged, of entities defined, concepts
899
+ realised at the logical level, logical entities realised by a table, logical entities with an owner or steward),
900
+ **Structure** (logical entities and tables the check finds nothing structural on), **Standards** (names keeping the
901
+ naming standard; none without one), **Readability** (boxes clear of each other, associations named),
902
+ **Definitions** (definitions more than the name and at least four words), **Consistency** (logical entities and
903
+ tables the check finds nothing inconsistent on). **Correctness**, **Scheme**, **Abstraction** and **Data** are for a
904
+ reviewer (`ScorecardCategory`). A reviewer's score and note, kept in the model (`model.scorecard.reviews`), override
905
+ a measured score too. The total is the weighted average of the categories with a score, with how much of the weight
906
+ that covers; weights are the model's own (`model.scorecard.weights`), equal (10 each) by default: the book gives its
907
+ own weighting, and an organisation sets the one it reviews by. Saving is one undo step (`scorecardCommand`).
908
+
909
+ ```javascript
910
+ model.scored().total(); // { score: 91, coverage: 50 }
911
+ ```
912
+
913
+ ```javascript
914
+ new SqlDdl().write(model); // 'CREATE TABLE party (
915
+ party_id BIGINT NOT NULL, …'
916
+ ```
814
917
  The ontology base keeps BIAN's **Agreement** (the contract) apart from its **Arrangement** (the terms a product is
815
918
  provided on), and has **Product Feature** and **Condition**; its concepts say which BIAN business object they are
816
919
  (`details.bian`, on hover).
@@ -849,6 +952,27 @@ types — see `ARCHITECTURE.md`):
849
952
  model.view({ level: DataModel.LANDSCAPE }); // { entities, folders, elementFolders, ... }
850
953
  ```
851
954
 
955
+ **Editing.** At a level of the schema, double-click an entity (or a relationship's line or Chen diamond) to edit it;
956
+ right-click one for Edit… and Delete, or the canvas for **New entity here…** and **New relationship…**; Model ▸ New
957
+ concept/entity/table… and New relationship… do the same. Each level says what its entities hold and gives its
958
+ dialog's fields (`DataModelNotation.level(name)`: a `ConceptualLevel` a name and a definition; a `LogicalLevel` and
959
+ a `PhysicalLevel`, both `AttributedLevel`s, the attributes or columns too, as a `rows` table: name, type (the model's
960
+ data types and plain types suggested at the logical level, SQL types at the physical), PK, FK, unique, required,
961
+ what a foreign key references, a definition), and reads it back over the entity (`entitySpecFrom`), so where it is
962
+ drawn and what the dialog does not show stay; `relationshipFields` and `relationshipSpecFrom` do the same for a
963
+ relationship (ends, cardinalities, name, identifying, definition). Every edit is one undo step, a
964
+ `DataModelEditCommand` (the model as it was before and after, `DataModel#restore` putting either back):
965
+ `saveEntityCommand(level, id|null, spec)`, `removeEntityCommand(level, id)` (its relationships and mapping pairs go,
966
+ and each perspective, service domain and context forgets it: `forgetEntity`), `saveRelationshipCommand(level,
967
+ index|null, spec)`, `removeRelationshipCommand(level, index)`; `relationshipIndex(level, drawn)` says which
968
+ relationship a line or a diamond is. These stand in for graphDiagram's own Rename and Delete, which change only
969
+ the drawing.
970
+
971
+ ```javascript
972
+ model.history.execute(model.saveEntityCommand('logical', null, { name: 'Phone', attributes: [{ name: 'number', required: true }] }));
973
+ model.history.undo(); // gone again
974
+ ```
975
+
852
976
  **Data types.** A model's `dataTypes` are the types its attributes have, each defined once: a `DataType` (a plain
853
977
  named type, `basedOn` another), an `EnumerationType` (`values: [{ name, description? }]`) or a `StructuredType`
854
978
  (`fields: [{ name, type?, description?, iso20022? }]`), its `kind` in a spec picking the class (`DataType.from`,
@@ -2430,6 +2554,11 @@ offers `text` as its first choice; any other field, a checkbox too, gets a check
2430
2554
  fields: every field on "Keep" showing the value they share, read-only fields left out.
2431
2555
  `onApply(values)` receives every field; `onClose(applied)` is told once when the dialog closes, whether it
2432
2556
  was applied (false for Cancel, Escape or a click outside), so a caller waiting on a choice can settle.
2557
+ A `rows` field (`RowsField`) edits a list as a table: `columns` `[{ key, label, type?: 'text'|'checkbox'|'select',
2558
+ choices?, suggestions?, placeholder?, width? }]`, `value` the items, `addLabel`; a row each, moved up and down or removed,
2559
+ **+ Add** for a new one. It reads as the items in their order, each the item it was made from with the columns laid
2560
+ over it (what no column shows is kept; an empty text or an unticked box leaves its key out), a new row left empty
2561
+ dropped. It takes the dialog's whole width, its label above it.
2433
2562
  `EdgeStyleDialog`, the grid-size and diagram-name prompts are all `FormDialog`s. A dialog fits the window
2434
2563
  (at most 90% of its height): its fields scroll between the title and the buttons, which stay in view, and
2435
2564
  dragging the title moves it. A `textarea` scrolls inside its own box (at most 40% of the window) and can be