@rse/specbook 1.3.2 → 1.4.0

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 (45) hide show
  1. package/README.md +5 -2
  2. package/dst/specbook-api.js +7 -5
  3. package/dst/specbook-cli.js +0 -0
  4. package/dst/specbook-cmd-export.js +2 -2
  5. package/dst/specbook-coverage.js +1 -1
  6. package/dst/specbook-diagram.d.ts +1 -1
  7. package/dst/specbook-diagram.js +9 -3
  8. package/dst/specbook-export-ast.d.ts +1 -1
  9. package/dst/specbook-export-ast.js +21 -4
  10. package/dst/specbook-export-code.d.ts +14 -0
  11. package/dst/specbook-export-code.js +155 -0
  12. package/dst/specbook-export-common.d.ts +4 -2
  13. package/dst/specbook-export-common.js +110 -6
  14. package/dst/specbook-export-diagram.d.ts +15 -0
  15. package/dst/specbook-export-diagram.js +211 -0
  16. package/dst/specbook-export-html-fold.d.ts +20 -0
  17. package/dst/specbook-export-html-fold.js +458 -0
  18. package/dst/specbook-export-html-render.d.ts +51 -0
  19. package/dst/specbook-export-html-render.js +749 -0
  20. package/dst/specbook-export-html-search.js +6 -5
  21. package/dst/specbook-export-html-template.d.ts +21 -0
  22. package/dst/specbook-export-html-template.js +282 -0
  23. package/dst/specbook-export-html-widget.d.ts +12 -0
  24. package/dst/specbook-export-html-widget.js +605 -0
  25. package/dst/specbook-export-html.css +325 -50
  26. package/dst/specbook-export-html.js +62 -1931
  27. package/dst/specbook-export-image.d.ts +2 -0
  28. package/dst/specbook-export-image.js +161 -9
  29. package/dst/specbook-export-md.js +60 -12
  30. package/dst/specbook-format-schema.d.ts +1 -1
  31. package/dst/specbook-format-schema.js +1 -1
  32. package/dst/specbook-format-spec.d.ts +1 -0
  33. package/dst/specbook-format-spec.js +1 -0
  34. package/dst/specbook-format.md +169 -17
  35. package/dst/specbook-format.yaml +224 -23
  36. package/dst/specbook-ignore.js +2 -0
  37. package/dst/specbook-link.js +21 -5
  38. package/dst/specbook-parse-common.d.ts +24 -0
  39. package/dst/specbook-parse-common.js +137 -10
  40. package/dst/specbook-parse-semantic.js +2 -0
  41. package/dst/specbook-parse-syntax.js +81 -20
  42. package/dst/specbook-parse.js +1 -1
  43. package/dst/specbook-theme.d.ts +1 -0
  44. package/dst/specbook-theme.js +2 -0
  45. package/package.json +13 -7
@@ -267,6 +267,7 @@
267
267
  states a fact or event, not a decision (a deliberate exclusion is the `SCOPE` of
268
268
  the Solution Vision or a `WONT` requirement instead).
269
269
  format:
270
+ type: compact
270
271
  maxTableColumns: 5
271
272
  props:
272
273
  - name: TYPE
@@ -341,6 +342,7 @@
341
342
  term from its siblings (e.g. `A Message submitted by an Attendee as ...`), so that
342
343
  the hierarchy and the definitions cross-check each other.
343
344
  format:
345
+ type: compact
344
346
  maxTableColumns: 5
345
347
  referenced:
346
348
  - "[[*]]"
@@ -352,8 +354,9 @@
352
354
  labeled: true
353
355
  qualified: true
354
356
  config:
355
- size-node-width-max: 440
357
+ size-node-width-max: 440
356
358
  size-node-height-scale: 1.75
359
+ hub-node-count-max: 3
357
360
  props:
358
361
  - name: TYPE
359
362
  desc: >
@@ -661,6 +664,17 @@
661
664
  maxTableColumns: 6
662
665
  referenced:
663
666
  - "[[USE-CASE:*]]"
667
+ diagram:
668
+ type: hub
669
+ center: self
670
+ nodes: "[[FR.REQUIREMENT:*]], [[NR.REQUIREMENT:*]], [[PREMISE:*]], [[RULE:*]],
671
+ [[USE-CASE:*]], [[DM.ENTITY:*]], [[FV.COMPONENT:*]], [[TEST-CASE:*]]"
672
+ labeled: true
673
+ qualified: true
674
+ config:
675
+ size-node-width-max: 440
676
+ size-node-height-scale: 1.75
677
+ hub-node-count-max: 3
664
678
  props:
665
679
  - name: PRIORITY
666
680
  desc: >
@@ -734,6 +748,7 @@
734
748
  config:
735
749
  size-node-width-max: 440
736
750
  size-node-height-scale: 1.75
751
+ hub-node-count-max: 3
737
752
  props:
738
753
  - name: PRIORITY
739
754
  desc: >
@@ -827,6 +842,18 @@
827
842
  maxTableColumns: 5
828
843
  referenced:
829
844
  - "[[TEST-CASE:*]]"
845
+ diagram:
846
+ type: hub
847
+ center: self
848
+ nodes: "[[RULE:*]], [[TERM:*]], [[FR.REQUIREMENT:*]], [[NR.REQUIREMENT:*]],
849
+ [[PREMISE:*]], [[WORKFLOW:*]], [[HANDOFF:*]], [[USE-CASE:*]], [[TRANSITION:*]],
850
+ [[PERMISSION:*]], [[TEST-CASE:*]]"
851
+ labeled: true
852
+ qualified: true
853
+ config:
854
+ size-node-width-max: 440
855
+ size-node-height-scale: 1.75
856
+ hub-node-count-max: 3
830
857
  props:
831
858
  - name: CATEGORY
832
859
  desc: >
@@ -1599,7 +1626,19 @@
1599
1626
  roles against entities. Any operation, state, or condition not covered by a
1600
1627
  permission of the role (or of a role it `INHERITS`) is forbidden.
1601
1628
  format:
1629
+ type: compact
1602
1630
  maxTableColumns: 8
1631
+ diagram:
1632
+ type: hub
1633
+ center: self
1634
+ nodes: "[[PERMISSION:*]], [[ROLE:*]], [[DM.ENTITY:*]], [[STATE:*]], [[TRANSITION:*]],
1635
+ [[RULE:*]], [[USE-CASE:*]], [[SCENARIO:*]], [[ENDPOINT:*]], [[TEST-CASE:*]]"
1636
+ labeled: true
1637
+ qualified: true
1638
+ config:
1639
+ size-node-width-max: 440
1640
+ size-node-height-scale: 1.75
1641
+ hub-node-count-max: 3
1603
1642
  props:
1604
1643
  - name: ROLE
1605
1644
  desc: >
@@ -2188,12 +2227,14 @@
2188
2227
  it rejects is its `TRADE-OFF`), and is not verifiable by a metric (a measurable
2189
2228
  quality bound is a Non-Functional Requirement instead).
2190
2229
  referenced:
2191
- - "[[PATTERN:*]]"
2230
+ - "[[DIALOG-PATTERN:*]]"
2231
+ format:
2232
+ type: compact
2192
2233
  diagram:
2193
2234
  type: hub
2194
2235
  center: self
2195
2236
  nodes: "[[PRINCIPLE:*]], [[PERSONA:*]], [[STEP:*]], [[USE-CASE:*]], [[CONVENTION:*]],
2196
- [[PATTERN:*]], [[ELEMENT:*]], [[DECISION:*]]"
2237
+ [[DIALOG-PATTERN:*]], [[ELEMENT:*]], [[DECISION:*]]"
2197
2238
  labeled: true
2198
2239
  qualified: true
2199
2240
  config:
@@ -2284,6 +2325,18 @@
2284
2325
  solution phrases what it says, not what it does (a behavior is an Interaction
2285
2326
  Concept principle instead) and not what a term means (a definition is a Domain
2286
2327
  Glossary term instead).
2328
+ format:
2329
+ type: compact
2330
+ diagram:
2331
+ type: hub
2332
+ center: self
2333
+ nodes: "[[CONVENTION:*]], [[PERSONA:*]], [[PRINCIPLE:*]], [[TERM:*]], [[DECISION:*]]"
2334
+ labeled: true
2335
+ qualified: true
2336
+ config:
2337
+ size-node-width-max: 440
2338
+ size-node-height-scale: 1.75
2339
+ hub-node-count-max: 3
2287
2340
  props:
2288
2341
  - name: CATEGORY
2289
2342
  desc: >
@@ -2338,7 +2391,7 @@
2338
2391
  optional: true
2339
2392
  diagram:
2340
2393
  type: grid
2341
- nodes: "[[PATTERN:*]]"
2394
+ nodes: "[[DIALOG-PATTERN:*]]"
2342
2395
  properties:
2343
2396
  - CATEGORY
2344
2397
  config:
@@ -2346,7 +2399,7 @@
2346
2399
  size-node-height-scale: 2
2347
2400
  grid-columns-max: 4
2348
2401
  children:
2349
- - kind: PATTERN
2402
+ - kind: DIALOG-PATTERN
2350
2403
  desc: >
2351
2404
  A single reusable dialog pattern, named with a short (2-5 word) summary (e.g.
2352
2405
  `Master-Detail`, `Wizard`, `Inline Edit`) and described in a concise (1-3 sentence)
@@ -2360,7 +2413,7 @@
2360
2413
  diagram:
2361
2414
  type: hub
2362
2415
  center: self
2363
- nodes: "[[PATTERN:*]], [[PRINCIPLE:*]], [[STORYBOARD:*]], [[DECISION:*]]"
2416
+ nodes: "[[DIALOG-PATTERN:*]], [[PRINCIPLE:*]], [[STORYBOARD:*]], [[DECISION:*]]"
2364
2417
  deep: true
2365
2418
  labeled: true
2366
2419
  qualified: true
@@ -2405,7 +2458,7 @@
2405
2458
  pattern is composed of (e.g. a `Master-Detail` using an `Inline Edit` in
2406
2459
  its detail), so that the patterns form a language of related structures
2407
2460
  rather than a flat catalogue.
2408
- value: list([[PATTERN:*]])
2461
+ value: list([[DIALOG-PATTERN:*]])
2409
2462
  optional: true
2410
2463
  - name: TRADE-OFF
2411
2464
  desc: >
@@ -2450,7 +2503,7 @@
2450
2503
  diagram:
2451
2504
  type: hub
2452
2505
  center: self
2453
- nodes: "[[STORYBOARD:*]], [[PERSONA:*]], [[SCENARIO:*]], [[PATTERN:*]], [[MOCKUP:*]]"
2506
+ nodes: "[[STORYBOARD:*]], [[PERSONA:*]], [[SCENARIO:*]], [[DIALOG-PATTERN:*]], [[MOCKUP:*]]"
2454
2507
  deep: true
2455
2508
  labeled: true
2456
2509
  qualified: true
@@ -2502,7 +2555,7 @@
2502
2555
  Comma-separated references to the DIALOG-PATTERNS objects the frame
2503
2556
  instantiates, so that a pattern is shown to recur across the
2504
2557
  concrete flows rather than merely being catalogued.
2505
- value: list([[PATTERN:*]])
2558
+ value: list([[DIALOG-PATTERN:*]])
2506
2559
  optional: true
2507
2560
  - name: SKETCH
2508
2561
  desc: >
@@ -2559,6 +2612,7 @@
2559
2612
  list of token values (the values are in the design system) or a measurable bound
2560
2613
  (a bound is a Non-Functional Requirement instead).
2561
2614
  format:
2615
+ type: compact
2562
2616
  maxTableColumns: 5
2563
2617
  diagram:
2564
2618
  type: hub
@@ -2568,6 +2622,7 @@
2568
2622
  qualified: true
2569
2623
  config:
2570
2624
  size-node-width-max: 440
2625
+ hub-node-count-max: 3
2571
2626
  props:
2572
2627
  - name: CATEGORY
2573
2628
  desc: >
@@ -2617,6 +2672,15 @@
2617
2672
  applied rather than stating them (a rule is an `ELEMENT` instead).
2618
2673
  format:
2619
2674
  type: complex
2675
+ diagram:
2676
+ type: hub
2677
+ center: self
2678
+ nodes: "[[MOCKUP:*]], [[PERSONA:*]], [[STORYBOARD:*]], [[ELEMENT:*]]"
2679
+ labeled: true
2680
+ qualified: true
2681
+ config:
2682
+ size-node-width-max: 440
2683
+ hub-node-count-max: 3
2620
2684
  props:
2621
2685
  - name: ACTORS
2622
2686
  desc: >
@@ -2691,6 +2755,7 @@
2691
2755
  Deployment View node instead -- only a party or system the solution merely consumes
2692
2756
  or serves belongs to the system context.
2693
2757
  format:
2758
+ type: compact
2694
2759
  maxTableColumns: 5
2695
2760
  props:
2696
2761
  - name: KIND
@@ -2808,12 +2873,14 @@
2808
2873
  with the components it depends on, plus a 1-sentence rationale ("why") for the
2809
2874
  component's existence and boundary.
2810
2875
  format:
2876
+ type: compact
2811
2877
  maxTableColumns: 5
2812
2878
  diagram:
2813
2879
  type: hub
2814
2880
  center: self
2815
2881
  nodes: "[[FV.COMPONENT:*]], [[FR.REQUIREMENT:*]], [[INTERFACE:*]], [[DM.ENTITY:*]],
2816
- [[UNIT:*]], [[NODE:*]], [[CONCERN:*]], [[TACTIC:*]], [[DECISION:*]]"
2882
+ [[UNIT:*]], [[NODE:*]], [[CONCERN:*]], [[TACTIC:*]], [[DECISION:*]],
2883
+ [[CODE-PATTERN:*]]"
2817
2884
  labeled: true
2818
2885
  qualified: true
2819
2886
  properties:
@@ -2821,6 +2888,7 @@
2821
2888
  config:
2822
2889
  size-node-width-max: 440
2823
2890
  size-node-height-scale: 1.75
2891
+ hub-node-count-max: 3
2824
2892
  props:
2825
2893
  - name: KIND
2826
2894
  desc: |
@@ -2950,11 +3018,13 @@
2950
3018
  carrying trade-off behind the choice is a Design Decisions decision
2951
3019
  referencing the component through `DECIDES`, and the functional components
2952
3020
  depending on the product reference it through `USED-BY`.
3021
+ format:
3022
+ type: compact
2953
3023
  diagram:
2954
3024
  type: hub
2955
3025
  center: self
2956
3026
  nodes: "[[TS.TIER:*.COMPONENT:*]], [[FV.COMPONENT:*]], [[CONCERN:*]],
2957
- [[TACTIC:*]], [[DECISION:*]]"
3027
+ [[TACTIC:*]], [[DECISION:*]], [[CODE-PATTERN:*]]"
2958
3028
  labeled: true
2959
3029
  qualified: true
2960
3030
  properties:
@@ -2963,6 +3033,7 @@
2963
3033
  config:
2964
3034
  size-node-width-max: 440
2965
3035
  size-node-height-scale: 1.75
3036
+ hub-node-count-max: 3
2966
3037
  props:
2967
3038
  - name: PRODUCT
2968
3039
  desc: >
@@ -3276,9 +3347,11 @@
3276
3347
  process: it names no concrete products (a Technology Stack `Build-Time` component
3277
3348
  states the product choice), does not restate the runtime structure (a Functionality
3278
3349
  View `Module` or `Subsystem` groups the logic), does not cover production
3279
- procedures (an Operations View concern does), and the trade-off that produced a
3280
- rule is a Design Decisions decision referencing the aspect through `AFFECTS`,
3281
- while the quality the rule protects (usually a `Maintainability` requirement) is
3350
+ procedures (an Operations View concern does), does not prescribe how a concern is
3351
+ coded (a Code Patterns pattern shows that as a listing), and the trade-off that
3352
+ produced a rule is a Design Decisions decision referencing the aspect through
3353
+ `AFFECTS`, while the quality the rule protects (usually a `Maintainability`
3354
+ requirement) is
3282
3355
  addressed by a Quality Perspectives tactic referencing the aspect through
3283
3356
  `AFFECTS`, too, so the hub diagram of an aspect shows the decision and the tactic
3284
3357
  behind it.
@@ -3353,6 +3426,7 @@
3353
3426
  config:
3354
3427
  size-node-width-max: 440
3355
3428
  size-node-height-scale: 1.75
3429
+ hub-node-count-max: 3
3356
3430
  props:
3357
3431
  - name: KIND
3358
3432
  desc: |
@@ -3455,6 +3529,7 @@
3455
3529
  config:
3456
3530
  size-node-width-max: 440
3457
3531
  size-node-height-scale: 1.75
3532
+ hub-node-count-max: 3
3458
3533
  props:
3459
3534
  - name: PART-OF
3460
3535
  desc: >
@@ -3534,6 +3609,7 @@
3534
3609
  config:
3535
3610
  size-node-width-max: 440
3536
3611
  size-node-height-scale: 1.75
3612
+ hub-node-count-max: 3
3537
3613
  props:
3538
3614
  - name: KIND
3539
3615
  desc: |
@@ -3629,6 +3705,7 @@
3629
3705
  config:
3630
3706
  size-node-width-max: 440
3631
3707
  size-node-height-scale: 1.75
3708
+ hub-node-count-max: 3
3632
3709
  props:
3633
3710
  - name: SCOPE
3634
3711
  desc: |
@@ -3700,6 +3777,7 @@
3700
3777
  config:
3701
3778
  size-node-width-max: 440
3702
3779
  size-node-height-scale: 1.75
3780
+ hub-node-count-max: 3
3703
3781
  props:
3704
3782
  - name: CATEGORY
3705
3783
  desc: |
@@ -3801,16 +3879,20 @@
3801
3879
  Design Decisions decision referencing the tactic through `DECIDES`, the product
3802
3880
  realizing the mechanism is a Technology Stack component referenced through
3803
3881
  `TOOLS`, the developer-facing rule about the source structure is an aspect of the
3804
- Development Aspects, and a mechanism driven solely by a `Constraint` requirement
3882
+ Development Aspects, the coded form of the mechanism is a Code Patterns pattern
3883
+ referencing the tactic through `REALIZES`, and a mechanism driven solely by a
3884
+ `Constraint` requirement
3805
3885
  (e.g. a hosting or budget mandate) protects no quality and is a Design Decisions
3806
3886
  decision alone -- only the mechanism, the quality it achieves, and the elements it
3807
3887
  shapes belong here.
3888
+ format:
3889
+ type: compact
3808
3890
  diagram:
3809
3891
  type: hub
3810
3892
  center: self
3811
3893
  nodes: "[[TACTIC:*]], [[NR.REQUIREMENT:*]], [[FV.COMPONENT:*]], [[UNIT:*]],
3812
3894
  [[ASPECT:*]], [[NODE:*]], [[DM.ENTITY:*]], [[CONCERN:*]], [[DECISION:*]],
3813
- [[TS.TIER:*.COMPONENT:*]], [[TEST-CASE:*]]"
3895
+ [[TS.TIER:*.COMPONENT:*]], [[CODE-PATTERN:*]], [[TEST-CASE:*]]"
3814
3896
  labeled: true
3815
3897
  qualified: true
3816
3898
  properties:
@@ -3885,9 +3967,10 @@
3885
3967
  file: 30-ARCH-DD-Design-Decisions.md
3886
3968
  desc: >
3887
3969
  The major decisions related to the solution design, each recording the forces at play, the
3888
- chosen response, and the reasoning that justifies it. The artifact is the last one of the
3889
- architecture, as a decision references the requirements forcing it, the elements it
3890
- shapes, and the tactics and products it chose, all of which precede it.
3970
+ chosen response, and the reasoning that justifies it. The artifact is the last
3971
+ decision-level one of the architecture, as a decision references the requirements forcing
3972
+ it, the elements it shapes, and the tactics and products it chose, all of which precede
3973
+ it, while the Code Patterns following it reference the decisions they implement.
3891
3974
  optional: true
3892
3975
  refs: >
3893
3976
  - Nygard: Documenting Architecture Decisions (2011),
@@ -3963,15 +4046,17 @@
3963
4046
  decision is under-justified. The rationale should make the decision feel earned,
3964
4047
  not asserted - if you delete the rationale and the decision suddenly looks
3965
4048
  arbitrary, the rationale was doing its job.
4049
+ format:
4050
+ type: complex
3966
4051
  diagram:
3967
4052
  type: hub
3968
4053
  center: self
3969
4054
  nodes: "[[DECISION:*]], [[NR.REQUIREMENT:*]], [[PREMISE:*]], [[DM.ENTITY:*]],
3970
4055
  [[LIFECYCLE:*]], [[ROLE:*]], [[INTERFACE:*]], [[TYPE:*]], [[ENDPOINT:*]],
3971
- [[PRINCIPLE:*]], [[CONVENTION:*]], [[PATTERN:*]], [[STORYBOARD:*]],
4056
+ [[PRINCIPLE:*]], [[CONVENTION:*]], [[DIALOG-PATTERN:*]], [[STORYBOARD:*]],
3972
4057
  [[ELEMENT:*]], [[CV.ENTITY:*]], [[FV.COMPONENT:*]], [[UNIT:*]], [[ASPECT:*]],
3973
4058
  [[DV.TIER:*]], [[AREA:*]], [[NODE:*]], [[NETWORK:*]], [[TACTIC:*]],
3974
- [[TS.TIER:*.COMPONENT:*]]"
4059
+ [[TS.TIER:*.COMPONENT:*]], [[CODE-PATTERN:*]]"
3975
4060
  labeled: true
3976
4061
  qualified: true
3977
4062
  properties:
@@ -4019,7 +4104,7 @@
4019
4104
  integrated); omitted for a decision shaping no modeled element.
4020
4105
  value: list([[DM.ENTITY:*]], [[LIFECYCLE:*]], [[ROLE:*]], [[INTERFACE:*]],
4021
4106
  [[TYPE:*]], [[ENDPOINT:*]], [[PRINCIPLE:*]], [[CONVENTION:*]],
4022
- [[PATTERN:*]], [[STORYBOARD:*]], [[ELEMENT:*]], [[CV.ENTITY:*]],
4107
+ [[DIALOG-PATTERN:*]], [[STORYBOARD:*]], [[ELEMENT:*]], [[CV.ENTITY:*]],
4023
4108
  [[FV.COMPONENT:*]], [[UNIT:*]], [[ASPECT:*]], [[DV.TIER:*]], [[AREA:*]],
4024
4109
  [[NODE:*]], [[NETWORK:*]])
4025
4110
  optional: true
@@ -4115,10 +4200,123 @@
4115
4200
  matrix of considered alternatives); and
4116
4201
  - links to strongly related decisions.
4117
4202
  optional: true
4203
+
4204
+ - kind: ARCH
4205
+ name: Code Patterns
4206
+ id: CP
4207
+ file: 31-ARCH-CP-Code-Patterns.md
4208
+ desc: >
4209
+ The implementation patterns the source code of the solution follows, each prescribing how
4210
+ one recurring concern (e.g. authorization enforcement, entity persistence, error
4211
+ propagation) is coded and showing it as a code listing. The artifact follows the Design
4212
+ Decisions, as a pattern is the coded form of the tactics and decisions preceding it, and
4213
+ is absent when the coding conventions are governed outside the specification (e.g. by
4214
+ repository-level contributor instructions).
4215
+ optional: true
4216
+ refs: >
4217
+ - Starke/Hruschka: arc42 Template: Crosscutting Concepts (2005),
4218
+ https://arc42.org/overview
4219
+ - Fowler: Patterns of Enterprise Application Architecture (2002),
4220
+ https://martinfowler.com/books/eaa.html
4221
+ - Beck: Implementation Patterns (2007),
4222
+ https://www.informit.com/store/implementation-patterns-9780321413093
4223
+ diagram:
4224
+ type: grid
4225
+ nodes: "[[CODE-PATTERN:*]]"
4226
+ config:
4227
+ size-node-width-max: 440
4228
+ grid-columns-max: 4
4229
+ children:
4230
+ - kind: CODE-PATTERN
4231
+ desc: >
4232
+ A single code pattern, named with a short (2-5 word) summary of the concern it
4233
+ codes (e.g. `Endpoint Authorization`, `Entity Persistence`, `Error Propagation`)
4234
+ and described in a concise (1-3 sentence) paragraph by the rule the code follows
4235
+ whenever the concern arises, plus a 1-sentence rationale ("why") for the rule.
4236
+
4237
+ The listing showing the pattern follows the description and its rationale as the
4238
+ elaboration of the pattern: either a fenced code block in the language of the
4239
+ pattern (e.g. ` ```ts start=10 mark=3-5 `, the parameters numbering the lines
4240
+ from `start` and marking the essential ones) or an embedded excerpt of an existing
4241
+ source file (e.g. `![Entity Persistence](src/persistence.ts#lines=10-30&mark=3-5)`,
4242
+ the fragment selecting and marking the lines), the latter preferred once the code
4243
+ exists, as the specification then never drifts from it. The listing is the
4244
+ canonical, idealized form of the pattern, not an exhaustive example, so it is kept
4245
+ short (typically 10-30 lines) and the prose names what the listing cannot: the
4246
+ places the pattern applies and the deviation it rules out (`AVOID`).
4247
+
4248
+ A pattern states how a concern is coded, and nothing else: the quality mechanism
4249
+ it implements is a Quality Perspectives tactic referenced through `REALIZES`, the
4250
+ trade-off that chose its approach over alternatives is a Design Decisions decision
4251
+ referenced through `DECIDED-BY` (a pattern weighs no alternatives itself), the
4252
+ product it codes against is a Technology Stack component referenced through
4253
+ `TOOLS`, and the rule about the source layout, build, or process it lives in is a
4254
+ Development Aspects aspect -- only the recurring code shape, the elements written
4255
+ that way, and the deviation ruled out belong here.
4256
+ format:
4257
+ type: complex
4258
+ diagram:
4259
+ type: hub
4260
+ center: self
4261
+ nodes: "[[CODE-PATTERN:*]], [[FV.COMPONENT:*]], [[UNIT:*]], [[DM.ENTITY:*]],
4262
+ [[ROLE:*]], [[INTERFACE:*]], [[ENDPOINT:*]], [[TS.TIER:*.COMPONENT:*]],
4263
+ [[TACTIC:*]], [[DECISION:*]]"
4264
+ labeled: true
4265
+ qualified: true
4266
+ config:
4267
+ size-node-width-max: 440
4268
+ props:
4269
+ - name: APPLIES-TO
4270
+ desc: >
4271
+ Comma-separated references to the FUNCTIONALITY-VIEW, CONCURRENCY-VIEW,
4272
+ DATA-MODEL, AUTHORIZATION-MODEL, INTERFACE-MODEL, or INTERFACE-ENDPOINTS
4273
+ objects whose code follows the pattern (e.g. the components persisting
4274
+ their entities this way, the roles and endpoints guarded by the check);
4275
+ omitted for a pattern applied throughout the code base.
4276
+ value: list([[FV.COMPONENT:*]], [[UNIT:*]], [[DM.ENTITY:*]], [[ROLE:*]],
4277
+ [[INTERFACE:*]], [[ENDPOINT:*]])
4278
+ optional: true
4279
+ - name: REALIZES
4280
+ desc: >
4281
+ Comma-separated references to the QUALITY-PERSPECTIVES tactics the pattern
4282
+ is the coded form of (e.g. the token check implementing the access
4283
+ security tactic); omitted for a pattern serving no modeled tactic.
4284
+ value: list([[TACTIC:*]])
4285
+ optional: true
4286
+ - name: DECIDED-BY
4287
+ desc: >
4288
+ Comma-separated references to the DESIGN-DECISIONS objects the pattern
4289
+ implements (e.g. the query builder usage following the decision against an
4290
+ ORM); omitted for a pattern behind which no recorded decision stands.
4291
+ value: list([[DECISION:*]])
4292
+ optional: true
4293
+ - name: TOOLS
4294
+ desc: >
4295
+ Comma-separated references to the TECHNOLOGY-STACK components the pattern
4296
+ codes against (e.g. the query builder, the logging library); omitted for a
4297
+ pattern using the language alone.
4298
+ value: list([[TS.TIER:*.COMPONENT:*]])
4299
+ optional: true
4300
+ - name: USES
4301
+ desc: >
4302
+ Comma-separated references to the smaller CODE-PATTERNS objects the pattern
4303
+ is composed of (e.g. an `Endpoint Authorization` using the `Error
4304
+ Propagation` for its rejections), so that the patterns form a language of
4305
+ related shapes rather than a flat catalogue.
4306
+ value: list([[CODE-PATTERN:*]])
4307
+ optional: true
4308
+ acyclic: true
4309
+ - name: AVOID
4310
+ desc: >
4311
+ The deviation the pattern rules out, stated as the concrete shape a
4312
+ developer would otherwise reach for (e.g. `SQL strings assembled in the
4313
+ request handlers`, `role checks in the client alone`); omitted when the
4314
+ rule has no tempting alternative.
4315
+ optional: true
4118
4316
  - kind: TEST
4119
4317
  name: Test Cases
4120
4318
  id: TC
4121
- file: 31-TEST-TC-Test-Cases.md
4319
+ file: 32-TEST-TC-Test-Cases.md
4122
4320
  desc: >
4123
4321
  The verifiable conditions and steps used to confirm that requirements, domain rules, use
4124
4322
  case scenarios, state transitions, and the mechanisms, procedures, and decisions of the
@@ -4182,6 +4380,8 @@
4182
4380
  concurrency unit when its collaboration or contention is exercised, an aspect of
4183
4381
  the Development Aspects or a Design Decisions decision when its rule is checked by
4184
4382
  an architectural fitness function (e.g. no dependency edge against the layering).
4383
+ format:
4384
+ type: compact
4185
4385
  diagram:
4186
4386
  type: hub
4187
4387
  center: self
@@ -4195,6 +4395,7 @@
4195
4395
  config:
4196
4396
  size-node-width-max: 440
4197
4397
  size-node-height-scale: 1.75
4398
+ hub-node-count-max: 3
4198
4399
  props:
4199
4400
  - name: VERIFIES
4200
4401
  desc: >
@@ -41,6 +41,8 @@ const compileRule = (line, base, nocase) => {
41
41
  const anchored = pattern.includes("/");
42
42
  if (pattern.startsWith("/"))
43
43
  pattern = pattern.slice(1);
44
+ if (pattern === "")
45
+ return null;
44
46
  /* a negated character class is "[!...]" in the wildmatch of Git,
45
47
  while picomatch knows the "[^...]" spelling only */
46
48
  pattern = pattern.replace(/\[!/g, "[^");
@@ -5,9 +5,24 @@
5
5
  */
6
6
  /* the Wiki-style reference syntax ("[[xxx]]") */
7
7
  export const referenceRegex = /\[\[([^[\]]+)\]\]/g;
8
- /* strip the inline code markup of a name or property value
9
- (preserved in the AST for rendering) for matching and labeling */
10
- export const plainText = (text) => text.replace(/`/g, "");
8
+ /* the fenced code blocks of a Markdown text (from the opening fence line
9
+ up to the closing fence line, or to the end of an unclosed one) */
10
+ const fenceRegex = /^[ \t]*(`{3,}|~{3,})[^\n]*(?:\n[\s\S]*?(?:\n[ \t]*\1[`~]*[ \t]*(?=\n|$)|(?![\s\S]))|(?![\s\S]))/gm;
11
+ /* apply a transformation to the parts of a text outside of its fenced
12
+ code blocks, which stay verbatim, as code carries no references */
13
+ const outsideFences = (text, apply) => {
14
+ let result = "";
15
+ let last = 0;
16
+ for (const m of text.matchAll(fenceRegex)) {
17
+ result += apply(text.slice(last, m.index)) + m[0];
18
+ last = m.index + m[0].length;
19
+ }
20
+ return result + apply(text.slice(last));
21
+ };
22
+ /* strip the fenced code blocks of a description and the inline code
23
+ markup of a name, property value, or description (preserved in the
24
+ AST for rendering) for matching and labeling */
25
+ export const plainText = (text) => text.replace(fenceRegex, "").replace(/`/g, "");
11
26
  /* provide the lookup structures of an index, built once on first use */
12
27
  const lookups = new WeakMap();
13
28
  const lookup = (index) => {
@@ -184,5 +199,6 @@ export const anchorPaths = (index) => {
184
199
  }
185
200
  return paths;
186
201
  };
187
- /* expand all references of a text via a per-reference replacer */
188
- export const expandReferences = (text, replace) => text.replace(referenceRegex, (_, reference) => replace(reference.trim()));
202
+ /* expand all references of a text via a per-reference replacer
203
+ (except inside its fenced code blocks) */
204
+ export const expandReferences = (text, replace) => outsideFences(text, (part) => part.replace(referenceRegex, (_, reference) => replace(reference.trim())));
@@ -31,6 +31,30 @@ export declare const becauseRegex: RegExp;
31
31
  export declare const embeddingRegex: RegExp;
32
32
  export declare const embeddingThemes: readonly ["light", "dark"];
33
33
  export declare const embeddingVariants: (reference: string) => string[];
34
+ export declare const pdfType = "application/pdf";
35
+ export declare const codeType = "text/x-code";
36
+ export declare const codeLanguage: (name: string) => string | undefined;
37
+ export declare const markedLines: (mark: string) => {
38
+ has: (line: number) => boolean;
39
+ };
40
+ type FenceInfo = {
41
+ lang: string;
42
+ params: Record<string, string>;
43
+ error?: string;
44
+ };
45
+ export declare const fenceInfo: (info: string | undefined) => FenceInfo;
46
+ export declare const embeddingFragment: (reference: string, type: string) => {
47
+ file: string;
48
+ params: Record<string, string>;
49
+ } | undefined;
50
+ export declare const embeddingFileType: (reference: string) => string | undefined;
34
51
  export declare const embeddingMimeType: (reference: string) => string | undefined;
35
52
  export declare const embeddingCount: (reference: string | undefined) => number;
36
53
  export declare const embeddingDataRegex: RegExp;
54
+ export type DarkMark = "invert" | "none";
55
+ export declare const darkMark: (content: string) => {
56
+ content: string;
57
+ dark?: DarkMark;
58
+ };
59
+ export declare const markDark: (content: string, dark: DarkMark) => string;
60
+ export {};