@transitrix/diagrams 1.0.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.
- package/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/__tests__/edge-path.test.d.ts +1 -0
- package/dist/__tests__/edge-path.test.js +39 -0
- package/dist/__tests__/scope.test.d.ts +1 -0
- package/dist/__tests__/scope.test.js +23 -0
- package/dist/__tests__/yaml-normalize.test.d.ts +1 -0
- package/dist/__tests__/yaml-normalize.test.js +148 -0
- package/dist/activities/__tests__/cpm.test.d.ts +1 -0
- package/dist/activities/__tests__/cpm.test.js +146 -0
- package/dist/activities/__tests__/gantt.test.d.ts +1 -0
- package/dist/activities/__tests__/gantt.test.js +224 -0
- package/dist/activities/__tests__/layout.test.d.ts +1 -0
- package/dist/activities/__tests__/layout.test.js +98 -0
- package/dist/activities/__tests__/validate.test.d.ts +1 -0
- package/dist/activities/__tests__/validate.test.js +363 -0
- package/dist/activities/cpm.d.ts +2 -0
- package/dist/activities/cpm.js +86 -0
- package/dist/activities/gantt.d.ts +6 -0
- package/dist/activities/gantt.js +250 -0
- package/dist/activities/index.d.ts +5 -0
- package/dist/activities/index.js +4 -0
- package/dist/activities/layout.d.ts +2 -0
- package/dist/activities/layout.js +103 -0
- package/dist/activities/types.d.ts +125 -0
- package/dist/activities/types.js +1 -0
- package/dist/activities/validate.d.ts +2 -0
- package/dist/activities/validate.js +326 -0
- package/dist/activity-card/__tests__/example.test.d.ts +1 -0
- package/dist/activity-card/__tests__/example.test.js +56 -0
- package/dist/activity-card/__tests__/layout.test.d.ts +1 -0
- package/dist/activity-card/__tests__/layout.test.js +57 -0
- package/dist/activity-card/__tests__/resolver.test.d.ts +1 -0
- package/dist/activity-card/__tests__/resolver.test.js +146 -0
- package/dist/activity-card/__tests__/validate.test.d.ts +1 -0
- package/dist/activity-card/__tests__/validate.test.js +116 -0
- package/dist/activity-card/index.d.ts +5 -0
- package/dist/activity-card/index.js +3 -0
- package/dist/activity-card/layout.d.ts +7 -0
- package/dist/activity-card/layout.js +167 -0
- package/dist/activity-card/resolver.d.ts +7 -0
- package/dist/activity-card/resolver.js +310 -0
- package/dist/activity-card/types.d.ts +175 -0
- package/dist/activity-card/types.js +20 -0
- package/dist/activity-card/validate.d.ts +3 -0
- package/dist/activity-card/validate.js +145 -0
- package/dist/actor/__tests__/validate.test.d.ts +1 -0
- package/dist/actor/__tests__/validate.test.js +57 -0
- package/dist/actor/index.d.ts +3 -0
- package/dist/actor/index.js +2 -0
- package/dist/actor/types.d.ts +20 -0
- package/dist/actor/types.js +4 -0
- package/dist/actor/validate.d.ts +2 -0
- package/dist/actor/validate.js +34 -0
- package/dist/applications/__tests__/validate.test.d.ts +1 -0
- package/dist/applications/__tests__/validate.test.js +223 -0
- package/dist/applications/index.d.ts +2 -0
- package/dist/applications/index.js +1 -0
- package/dist/applications/types.d.ts +39 -0
- package/dist/applications/types.js +1 -0
- package/dist/applications/validate.d.ts +3 -0
- package/dist/applications/validate.js +109 -0
- package/dist/assertion/__tests__/example.test.d.ts +1 -0
- package/dist/assertion/__tests__/example.test.js +32 -0
- package/dist/assertion/__tests__/validate.test.d.ts +1 -0
- package/dist/assertion/__tests__/validate.test.js +130 -0
- package/dist/assertion/index.d.ts +4 -0
- package/dist/assertion/index.js +2 -0
- package/dist/assertion/types.d.ts +43 -0
- package/dist/assertion/types.js +7 -0
- package/dist/assertion/validate.d.ts +9 -0
- package/dist/assertion/validate.js +137 -0
- package/dist/blocks/__tests__/layout.test.d.ts +1 -0
- package/dist/blocks/__tests__/layout.test.js +153 -0
- package/dist/blocks/__tests__/validate.test.d.ts +1 -0
- package/dist/blocks/__tests__/validate.test.js +235 -0
- package/dist/blocks/index.d.ts +4 -0
- package/dist/blocks/index.js +2 -0
- package/dist/blocks/layout.d.ts +4 -0
- package/dist/blocks/layout.js +145 -0
- package/dist/blocks/types.d.ts +56 -0
- package/dist/blocks/types.js +1 -0
- package/dist/blocks/validate.d.ts +9 -0
- package/dist/blocks/validate.js +186 -0
- package/dist/capability-map/__tests__/validate.test.d.ts +1 -0
- package/dist/capability-map/__tests__/validate.test.js +212 -0
- package/dist/capability-map/index.d.ts +2 -0
- package/dist/capability-map/index.js +1 -0
- package/dist/capability-map/types.d.ts +26 -0
- package/dist/capability-map/types.js +1 -0
- package/dist/capability-map/validate.d.ts +3 -0
- package/dist/capability-map/validate.js +103 -0
- package/dist/change/__tests__/validate.test.d.ts +1 -0
- package/dist/change/__tests__/validate.test.js +73 -0
- package/dist/change/index.d.ts +2 -0
- package/dist/change/index.js +1 -0
- package/dist/change/types.d.ts +17 -0
- package/dist/change/types.js +3 -0
- package/dist/change/validate.d.ts +2 -0
- package/dist/change/validate.js +57 -0
- package/dist/compliance/__tests__/classify.test.d.ts +1 -0
- package/dist/compliance/__tests__/classify.test.js +24 -0
- package/dist/compliance/__tests__/confidence.test.d.ts +1 -0
- package/dist/compliance/__tests__/confidence.test.js +78 -0
- package/dist/compliance/__tests__/coverage-metric.test.d.ts +1 -0
- package/dist/compliance/__tests__/coverage-metric.test.js +164 -0
- package/dist/compliance/__tests__/demo-scenario.test.d.ts +1 -0
- package/dist/compliance/__tests__/demo-scenario.test.js +226 -0
- package/dist/compliance/__tests__/example.test.d.ts +1 -0
- package/dist/compliance/__tests__/example.test.js +51 -0
- package/dist/compliance/__tests__/gap-report.test.d.ts +1 -0
- package/dist/compliance/__tests__/gap-report.test.js +113 -0
- package/dist/compliance/__tests__/html.test.d.ts +1 -0
- package/dist/compliance/__tests__/html.test.js +122 -0
- package/dist/compliance/__tests__/impact.test.d.ts +1 -0
- package/dist/compliance/__tests__/impact.test.js +410 -0
- package/dist/compliance/__tests__/markdown.test.d.ts +1 -0
- package/dist/compliance/__tests__/markdown.test.js +85 -0
- package/dist/compliance/__tests__/views.test.d.ts +1 -0
- package/dist/compliance/__tests__/views.test.js +59 -0
- package/dist/compliance/classify.d.ts +27 -0
- package/dist/compliance/classify.js +60 -0
- package/dist/compliance/confidence.d.ts +27 -0
- package/dist/compliance/confidence.js +43 -0
- package/dist/compliance/coverage-metric.d.ts +74 -0
- package/dist/compliance/coverage-metric.js +181 -0
- package/dist/compliance/gap-report.d.ts +20 -0
- package/dist/compliance/gap-report.js +64 -0
- package/dist/compliance/html.d.ts +22 -0
- package/dist/compliance/html.js +256 -0
- package/dist/compliance/impact.d.ts +251 -0
- package/dist/compliance/impact.js +464 -0
- package/dist/compliance/index.d.ts +16 -0
- package/dist/compliance/index.js +9 -0
- package/dist/compliance/markdown.d.ts +18 -0
- package/dist/compliance/markdown.js +129 -0
- package/dist/compliance/reverse-index.d.ts +8 -0
- package/dist/compliance/reverse-index.js +30 -0
- package/dist/compliance/types.d.ts +98 -0
- package/dist/compliance/types.js +5 -0
- package/dist/compliance/views.d.ts +14 -0
- package/dist/compliance/views.js +35 -0
- package/dist/compliance-matrix/__tests__/build.test.d.ts +1 -0
- package/dist/compliance-matrix/__tests__/build.test.js +183 -0
- package/dist/compliance-matrix/__tests__/example.test.d.ts +1 -0
- package/dist/compliance-matrix/__tests__/example.test.js +49 -0
- package/dist/compliance-matrix/build.d.ts +18 -0
- package/dist/compliance-matrix/build.js +0 -0
- package/dist/compliance-matrix/index.d.ts +2 -0
- package/dist/compliance-matrix/index.js +1 -0
- package/dist/compliance-matrix/types.d.ts +86 -0
- package/dist/compliance-matrix/types.js +8 -0
- package/dist/confidence/__tests__/score.test.d.ts +1 -0
- package/dist/confidence/__tests__/score.test.js +188 -0
- package/dist/confidence/index.d.ts +2 -0
- package/dist/confidence/index.js +1 -0
- package/dist/confidence/score.d.ts +62 -0
- package/dist/confidence/score.js +215 -0
- package/dist/confidence/types.d.ts +79 -0
- package/dist/confidence/types.js +6 -0
- package/dist/edge-path.d.ts +18 -0
- package/dist/edge-path.js +35 -0
- package/dist/element-envelope.d.ts +15 -0
- package/dist/element-envelope.js +55 -0
- package/dist/factor/__tests__/validate.test.d.ts +1 -0
- package/dist/factor/__tests__/validate.test.js +83 -0
- package/dist/factor/index.d.ts +3 -0
- package/dist/factor/index.js +2 -0
- package/dist/factor/types.d.ts +23 -0
- package/dist/factor/types.js +6 -0
- package/dist/factor/validate.d.ts +2 -0
- package/dist/factor/validate.js +69 -0
- package/dist/fgca/__tests__/chain-table.test.d.ts +1 -0
- package/dist/fgca/__tests__/chain-table.test.js +158 -0
- package/dist/fgca/__tests__/layout.test.d.ts +1 -0
- package/dist/fgca/__tests__/layout.test.js +140 -0
- package/dist/fgca/__tests__/parse-canonical.test.d.ts +1 -0
- package/dist/fgca/__tests__/parse-canonical.test.js +224 -0
- package/dist/fgca/__tests__/preview-layout.test.d.ts +1 -0
- package/dist/fgca/__tests__/preview-layout.test.js +106 -0
- package/dist/fgca/__tests__/validate.test.d.ts +1 -0
- package/dist/fgca/__tests__/validate.test.js +125 -0
- package/dist/fgca/chain-table.d.ts +36 -0
- package/dist/fgca/chain-table.js +177 -0
- package/dist/fgca/index.d.ts +16 -0
- package/dist/fgca/index.js +11 -0
- package/dist/fgca/layout.d.ts +27 -0
- package/dist/fgca/layout.js +156 -0
- package/dist/fgca/nodeTypes.d.ts +6 -0
- package/dist/fgca/nodeTypes.js +10 -0
- package/dist/fgca/nodes/FGCAActivityNode.d.ts +13 -0
- package/dist/fgca/nodes/FGCAActivityNode.js +35 -0
- package/dist/fgca/nodes/FGCAChangeNode.d.ts +12 -0
- package/dist/fgca/nodes/FGCAChangeNode.js +35 -0
- package/dist/fgca/nodes/FGCAFactorNode.d.ts +12 -0
- package/dist/fgca/nodes/FGCAFactorNode.js +35 -0
- package/dist/fgca/nodes/FGCAGoalNode.d.ts +14 -0
- package/dist/fgca/nodes/FGCAGoalNode.js +40 -0
- package/dist/fgca/parse-canonical.d.ts +58 -0
- package/dist/fgca/parse-canonical.js +339 -0
- package/dist/fgca/preview-layout.d.ts +87 -0
- package/dist/fgca/preview-layout.js +122 -0
- package/dist/fgca/types.d.ts +39 -0
- package/dist/fgca/types.js +7 -0
- package/dist/fgca/validate.d.ts +14 -0
- package/dist/fgca/validate.js +108 -0
- package/dist/geometry.d.ts +7 -0
- package/dist/geometry.js +2 -0
- package/dist/goals/__tests__/layout.test.d.ts +1 -0
- package/dist/goals/__tests__/layout.test.js +153 -0
- package/dist/goals/__tests__/mutations.test.d.ts +1 -0
- package/dist/goals/__tests__/mutations.test.js +95 -0
- package/dist/goals/__tests__/parse-canonical.test.d.ts +1 -0
- package/dist/goals/__tests__/parse-canonical.test.js +129 -0
- package/dist/goals/__tests__/validate.test.d.ts +1 -0
- package/dist/goals/__tests__/validate.test.js +183 -0
- package/dist/goals/index.d.ts +6 -0
- package/dist/goals/index.js +4 -0
- package/dist/goals/layout.d.ts +11 -0
- package/dist/goals/layout.js +147 -0
- package/dist/goals/mutations.d.ts +6 -0
- package/dist/goals/mutations.js +116 -0
- package/dist/goals/parse-canonical.d.ts +29 -0
- package/dist/goals/parse-canonical.js +257 -0
- package/dist/goals/types.d.ts +71 -0
- package/dist/goals/types.js +1 -0
- package/dist/goals/validate.d.ts +2 -0
- package/dist/goals/validate.js +122 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +23 -0
- package/dist/issues/__tests__/layout.test.d.ts +1 -0
- package/dist/issues/__tests__/layout.test.js +62 -0
- package/dist/issues/__tests__/validate.test.d.ts +1 -0
- package/dist/issues/__tests__/validate.test.js +82 -0
- package/dist/issues/index.d.ts +4 -0
- package/dist/issues/index.js +2 -0
- package/dist/issues/layout.d.ts +10 -0
- package/dist/issues/layout.js +82 -0
- package/dist/issues/types.d.ts +61 -0
- package/dist/issues/types.js +6 -0
- package/dist/issues/validate.d.ts +3 -0
- package/dist/issues/validate.js +143 -0
- package/dist/process-blueprint/__tests__/compliance-lane.test.d.ts +1 -0
- package/dist/process-blueprint/__tests__/compliance-lane.test.js +272 -0
- package/dist/process-blueprint/__tests__/layout.test.d.ts +1 -0
- package/dist/process-blueprint/__tests__/layout.test.js +159 -0
- package/dist/process-blueprint/__tests__/validate.test.d.ts +1 -0
- package/dist/process-blueprint/__tests__/validate.test.js +280 -0
- package/dist/process-blueprint/index.d.ts +4 -0
- package/dist/process-blueprint/index.js +2 -0
- package/dist/process-blueprint/layout.d.ts +2 -0
- package/dist/process-blueprint/layout.js +416 -0
- package/dist/process-blueprint/types.d.ts +220 -0
- package/dist/process-blueprint/types.js +1 -0
- package/dist/process-blueprint/validate.d.ts +3 -0
- package/dist/process-blueprint/validate.js +165 -0
- package/dist/process-map/__tests__/validate.test.d.ts +1 -0
- package/dist/process-map/__tests__/validate.test.js +199 -0
- package/dist/process-map/index.d.ts +2 -0
- package/dist/process-map/index.js +1 -0
- package/dist/process-map/types.d.ts +32 -0
- package/dist/process-map/types.js +1 -0
- package/dist/process-map/validate.d.ts +3 -0
- package/dist/process-map/validate.js +115 -0
- package/dist/products/__tests__/validate.test.d.ts +1 -0
- package/dist/products/__tests__/validate.test.js +210 -0
- package/dist/products/index.d.ts +2 -0
- package/dist/products/index.js +1 -0
- package/dist/products/types.d.ts +28 -0
- package/dist/products/types.js +1 -0
- package/dist/products/validate.d.ts +3 -0
- package/dist/products/validate.js +93 -0
- package/dist/repo-validate/__tests__/validate-repo.test.d.ts +1 -0
- package/dist/repo-validate/__tests__/validate-repo.test.js +132 -0
- package/dist/repo-validate/index.d.ts +2 -0
- package/dist/repo-validate/index.js +1 -0
- package/dist/repo-validate/types.d.ts +34 -0
- package/dist/repo-validate/types.js +14 -0
- package/dist/repo-validate/validate-repo.d.ts +8 -0
- package/dist/repo-validate/validate-repo.js +189 -0
- package/dist/requirement/__tests__/example.test.d.ts +1 -0
- package/dist/requirement/__tests__/example.test.js +21 -0
- package/dist/requirement/__tests__/validate.test.d.ts +1 -0
- package/dist/requirement/__tests__/validate.test.js +80 -0
- package/dist/requirement/index.d.ts +4 -0
- package/dist/requirement/index.js +2 -0
- package/dist/requirement/types.d.ts +25 -0
- package/dist/requirement/types.js +4 -0
- package/dist/requirement/validate.d.ts +7 -0
- package/dist/requirement/validate.js +81 -0
- package/dist/scenarios/__tests__/validate.test.d.ts +1 -0
- package/dist/scenarios/__tests__/validate.test.js +183 -0
- package/dist/scenarios/index.d.ts +2 -0
- package/dist/scenarios/index.js +1 -0
- package/dist/scenarios/types.d.ts +45 -0
- package/dist/scenarios/types.js +1 -0
- package/dist/scenarios/validate.d.ts +3 -0
- package/dist/scenarios/validate.js +110 -0
- package/dist/schema-version.d.ts +16 -0
- package/dist/schema-version.js +16 -0
- package/dist/scope.d.ts +23 -0
- package/dist/scope.js +38 -0
- package/dist/stakeholder/__tests__/validate.test.d.ts +1 -0
- package/dist/stakeholder/__tests__/validate.test.js +86 -0
- package/dist/stakeholder/index.d.ts +3 -0
- package/dist/stakeholder/index.js +2 -0
- package/dist/stakeholder/types.d.ts +24 -0
- package/dist/stakeholder/types.js +5 -0
- package/dist/stakeholder/validate.d.ts +2 -0
- package/dist/stakeholder/validate.js +58 -0
- package/dist/target-state/__tests__/validate.test.d.ts +1 -0
- package/dist/target-state/__tests__/validate.test.js +62 -0
- package/dist/target-state/index.d.ts +2 -0
- package/dist/target-state/index.js +1 -0
- package/dist/target-state/types.d.ts +18 -0
- package/dist/target-state/types.js +7 -0
- package/dist/target-state/validate.d.ts +2 -0
- package/dist/target-state/validate.js +61 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.js +2 -0
- package/dist/theme/themes.d.ts +16 -0
- package/dist/theme/themes.js +213 -0
- package/dist/theme/tokens.d.ts +158 -0
- package/dist/theme/tokens.js +105 -0
- package/dist/typed-id.d.ts +20 -0
- package/dist/typed-id.js +38 -0
- package/dist/validation-types.d.ts +34 -0
- package/dist/validation-types.js +1 -0
- package/dist/webview/__tests__/entry-notations.test.d.ts +1 -0
- package/dist/webview/__tests__/entry-notations.test.js +62 -0
- package/dist/webview/__tests__/entry.test.d.ts +1 -0
- package/dist/webview/__tests__/entry.test.js +56 -0
- package/dist/webview/__tests__/render-goals.test.d.ts +1 -0
- package/dist/webview/__tests__/render-goals.test.js +65 -0
- package/dist/webview/entry.d.ts +38 -0
- package/dist/webview/entry.js +182 -0
- package/dist/webview/render-activities.d.ts +24 -0
- package/dist/webview/render-activities.js +127 -0
- package/dist/webview/render-activity-card.d.ts +5 -0
- package/dist/webview/render-activity-card.js +168 -0
- package/dist/webview/render-applications.d.ts +11 -0
- package/dist/webview/render-applications.js +105 -0
- package/dist/webview/render-blocks.d.ts +5 -0
- package/dist/webview/render-blocks.js +71 -0
- package/dist/webview/render-capability-map.d.ts +7 -0
- package/dist/webview/render-capability-map.js +88 -0
- package/dist/webview/render-fgca.d.ts +8 -0
- package/dist/webview/render-fgca.js +94 -0
- package/dist/webview/render-goals.d.ts +6 -0
- package/dist/webview/render-goals.js +92 -0
- package/dist/webview/render-process-blueprint.d.ts +5 -0
- package/dist/webview/render-process-blueprint.js +135 -0
- package/dist/webview/render-process-map.d.ts +7 -0
- package/dist/webview/render-process-map.js +82 -0
- package/dist/webview/render-products.d.ts +7 -0
- package/dist/webview/render-products.js +81 -0
- package/dist/webview/render-scenarios.d.ts +7 -0
- package/dist/webview/render-scenarios.js +75 -0
- package/dist/webview/render-util.d.ts +16 -0
- package/dist/webview/render-util.js +31 -0
- package/dist/webview/transitrix-render.css +323 -0
- package/dist/webview/transitrix-render.js +6452 -0
- package/dist/webview/transitrix-render.js.map +7 -0
- package/dist/yaml-normalize.d.ts +20 -0
- package/dist/yaml-normalize.js +57 -0
- package/package.json +40 -0
- package/src/__tests__/edge-path.test.ts +46 -0
- package/src/__tests__/scope.test.ts +27 -0
- package/src/__tests__/yaml-normalize.test.ts +158 -0
- package/src/activities/__tests__/cpm.test.ts +164 -0
- package/src/activities/__tests__/gantt.test.ts +245 -0
- package/src/activities/__tests__/layout.test.ts +112 -0
- package/src/activities/__tests__/validate.test.ts +409 -0
- package/src/activities/cpm.ts +95 -0
- package/src/activities/gantt.ts +276 -0
- package/src/activities/index.ts +28 -0
- package/src/activities/layout.ts +112 -0
- package/src/activities/types.ts +148 -0
- package/src/activities/validate.ts +357 -0
- package/src/activity-card/__tests__/example.test.ts +66 -0
- package/src/activity-card/__tests__/layout.test.ts +63 -0
- package/src/activity-card/__tests__/resolver.test.ts +161 -0
- package/src/activity-card/__tests__/validate.test.ts +131 -0
- package/src/activity-card/index.ts +32 -0
- package/src/activity-card/layout.ts +194 -0
- package/src/activity-card/resolver.ts +337 -0
- package/src/activity-card/types.ts +237 -0
- package/src/activity-card/validate.ts +158 -0
- package/src/actor/__tests__/validate.test.ts +67 -0
- package/src/actor/index.ts +3 -0
- package/src/actor/types.ts +29 -0
- package/src/actor/validate.ts +38 -0
- package/src/applications/__tests__/validate.test.ts +256 -0
- package/src/applications/index.ts +11 -0
- package/src/applications/types.ts +43 -0
- package/src/applications/validate.ts +131 -0
- package/src/assertion/__tests__/example.test.ts +37 -0
- package/src/assertion/__tests__/validate.test.ts +142 -0
- package/src/assertion/index.ts +12 -0
- package/src/assertion/types.ts +58 -0
- package/src/assertion/validate.ts +145 -0
- package/src/blocks/__tests__/layout.test.ts +169 -0
- package/src/blocks/__tests__/validate.test.ts +260 -0
- package/src/blocks/index.ts +17 -0
- package/src/blocks/layout.ts +186 -0
- package/src/blocks/types.ts +62 -0
- package/src/blocks/validate.ts +206 -0
- package/src/capability-map/__tests__/validate.test.ts +238 -0
- package/src/capability-map/index.ts +8 -0
- package/src/capability-map/types.ts +29 -0
- package/src/capability-map/validate.ts +127 -0
- package/src/change/__tests__/validate.test.ts +88 -0
- package/src/change/index.ts +2 -0
- package/src/change/types.ts +23 -0
- package/src/change/validate.ts +61 -0
- package/src/compliance/__tests__/classify.test.ts +27 -0
- package/src/compliance/__tests__/confidence.test.ts +98 -0
- package/src/compliance/__tests__/coverage-metric.test.ts +188 -0
- package/src/compliance/__tests__/demo-scenario.test.ts +273 -0
- package/src/compliance/__tests__/example.test.ts +57 -0
- package/src/compliance/__tests__/gap-report.test.ts +129 -0
- package/src/compliance/__tests__/html.test.ts +142 -0
- package/src/compliance/__tests__/impact.test.ts +482 -0
- package/src/compliance/__tests__/markdown.test.ts +95 -0
- package/src/compliance/__tests__/views.test.ts +64 -0
- package/src/compliance/classify.ts +84 -0
- package/src/compliance/confidence.ts +69 -0
- package/src/compliance/coverage-metric.ts +263 -0
- package/src/compliance/gap-report.ts +94 -0
- package/src/compliance/html.ts +295 -0
- package/src/compliance/impact.ts +677 -0
- package/src/compliance/index.ts +56 -0
- package/src/compliance/markdown.ts +135 -0
- package/src/compliance/reverse-index.ts +33 -0
- package/src/compliance/types.ts +120 -0
- package/src/compliance/views.ts +46 -0
- package/src/compliance-matrix/__tests__/build.test.ts +200 -0
- package/src/compliance-matrix/__tests__/example.test.ts +57 -0
- package/src/compliance-matrix/build.ts +0 -0
- package/src/compliance-matrix/index.ts +11 -0
- package/src/compliance-matrix/types.ts +102 -0
- package/src/confidence/__tests__/score.test.ts +254 -0
- package/src/confidence/index.ts +21 -0
- package/src/confidence/score.ts +243 -0
- package/src/confidence/types.ts +96 -0
- package/src/edge-path.ts +44 -0
- package/src/element-envelope.ts +76 -0
- package/src/factor/__tests__/validate.test.ts +98 -0
- package/src/factor/index.ts +8 -0
- package/src/factor/types.ts +41 -0
- package/src/factor/validate.ts +74 -0
- package/src/fgca/__tests__/chain-table.test.ts +172 -0
- package/src/fgca/__tests__/layout.test.ts +179 -0
- package/src/fgca/__tests__/parse-canonical.test.ts +248 -0
- package/src/fgca/__tests__/preview-layout.test.ts +124 -0
- package/src/fgca/__tests__/validate.test.ts +142 -0
- package/src/fgca/chain-table.ts +225 -0
- package/src/fgca/index.ts +45 -0
- package/src/fgca/layout.ts +204 -0
- package/src/fgca/nodeTypes.ts +11 -0
- package/src/fgca/nodes/FGCAActivityNode.tsx +65 -0
- package/src/fgca/nodes/FGCAChangeNode.tsx +64 -0
- package/src/fgca/nodes/FGCAFactorNode.tsx +64 -0
- package/src/fgca/nodes/FGCAGoalNode.tsx +72 -0
- package/src/fgca/parse-canonical.ts +400 -0
- package/src/fgca/preview-layout.ts +217 -0
- package/src/fgca/types.ts +50 -0
- package/src/fgca/validate.ts +126 -0
- package/src/geometry.ts +9 -0
- package/src/goals/__tests__/layout.test.ts +175 -0
- package/src/goals/__tests__/mutations.test.ts +111 -0
- package/src/goals/__tests__/parse-canonical.test.ts +145 -0
- package/src/goals/__tests__/validate.test.ts +202 -0
- package/src/goals/index.ts +21 -0
- package/src/goals/layout.ts +172 -0
- package/src/goals/mutations.ts +123 -0
- package/src/goals/parse-canonical.ts +286 -0
- package/src/goals/types.ts +85 -0
- package/src/goals/validate.ts +136 -0
- package/src/index.ts +23 -0
- package/src/process-blueprint/__tests__/compliance-lane.test.ts +320 -0
- package/src/process-blueprint/__tests__/layout.test.ts +195 -0
- package/src/process-blueprint/__tests__/validate.test.ts +310 -0
- package/src/process-blueprint/index.ts +31 -0
- package/src/process-blueprint/layout.ts +531 -0
- package/src/process-blueprint/types.ts +242 -0
- package/src/process-blueprint/validate.ts +181 -0
- package/src/process-map/__tests__/validate.test.ts +223 -0
- package/src/process-map/index.ts +10 -0
- package/src/process-map/types.ts +36 -0
- package/src/process-map/validate.ts +135 -0
- package/src/products/__tests__/validate.test.ts +239 -0
- package/src/products/index.ts +9 -0
- package/src/products/types.ts +31 -0
- package/src/products/validate.ts +112 -0
- package/src/repo-validate/__tests__/validate-repo.test.ts +149 -0
- package/src/repo-validate/index.ts +2 -0
- package/src/repo-validate/types.ts +50 -0
- package/src/repo-validate/validate-repo.ts +196 -0
- package/src/requirement/__tests__/example.test.ts +24 -0
- package/src/requirement/__tests__/validate.test.ts +96 -0
- package/src/requirement/index.ts +4 -0
- package/src/requirement/types.ts +35 -0
- package/src/requirement/validate.ts +92 -0
- package/src/scenarios/__tests__/validate.test.ts +209 -0
- package/src/scenarios/index.ts +15 -0
- package/src/scenarios/types.ts +37 -0
- package/src/scenarios/validate.ts +122 -0
- package/src/schema-version.ts +16 -0
- package/src/scope.ts +46 -0
- package/src/stakeholder/__tests__/validate.test.ts +101 -0
- package/src/stakeholder/index.ts +3 -0
- package/src/stakeholder/types.ts +33 -0
- package/src/stakeholder/validate.ts +63 -0
- package/src/target-state/__tests__/validate.test.ts +74 -0
- package/src/target-state/index.ts +2 -0
- package/src/target-state/types.ts +28 -0
- package/src/target-state/validate.ts +67 -0
- package/src/theme/index.ts +4 -0
- package/src/theme/themes.ts +237 -0
- package/src/theme/tokens.ts +133 -0
- package/src/typed-id.ts +56 -0
- package/src/validation-types.ts +36 -0
- package/src/webview/__tests__/entry-notations.test.ts +77 -0
- package/src/webview/__tests__/entry.test.ts +64 -0
- package/src/webview/__tests__/render-goals.test.ts +72 -0
- package/src/webview/entry.ts +292 -0
- package/src/webview/render-activities.ts +156 -0
- package/src/webview/render-activity-card.ts +234 -0
- package/src/webview/render-applications.ts +123 -0
- package/src/webview/render-blocks.ts +91 -0
- package/src/webview/render-capability-map.ts +98 -0
- package/src/webview/render-fgca.ts +122 -0
- package/src/webview/render-goals.ts +110 -0
- package/src/webview/render-process-blueprint.ts +207 -0
- package/src/webview/render-process-map.ts +93 -0
- package/src/webview/render-products.ts +91 -0
- package/src/webview/render-scenarios.ts +90 -0
- package/src/webview/render-util.ts +34 -0
- package/src/webview/styles.css +323 -0
- package/src/yaml-normalize.ts +56 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Step 4 parity check: every supported notation must render through the
|
|
3
|
+
* webview bundle's `render(kind, source)` API from the same example fixtures
|
|
4
|
+
* the VS Code previews consume — a valid document yields `status: 'ok'` with
|
|
5
|
+
* non-empty markup, and a malformed document degrades to the error panel
|
|
6
|
+
* (structured errors, no thrown exception reaching the JVM host).
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync } from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
import { describe, expect, it } from 'vitest';
|
|
13
|
+
|
|
14
|
+
import { api, render, type NotationKind } from '../entry.js';
|
|
15
|
+
|
|
16
|
+
const EXAMPLES = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../../tests/fixtures/notation-corpus');
|
|
17
|
+
|
|
18
|
+
interface Fixture {
|
|
19
|
+
kind: NotationKind;
|
|
20
|
+
file: string;
|
|
21
|
+
/** The markup wrapper the renderer emits: an <svg> diagram or an HTML <section>. */
|
|
22
|
+
markup: 'svg' | 'section';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Mirrors the fixtures used by the VS Code previews. One representative
|
|
26
|
+
// example per notation is enough to prove the dispatch + renderer wiring.
|
|
27
|
+
const FIXTURES: Fixture[] = [
|
|
28
|
+
{ kind: 'goals', file: 'goals/strategy-2026.goals.transitrix.yaml', markup: 'svg' },
|
|
29
|
+
{ kind: 'fgca', file: 'fgca/strategy-2026.fgca.transitrix.yaml', markup: 'svg' },
|
|
30
|
+
{ kind: 'fga', file: 'fga/strategy-2026.fga.transitrix.yaml', markup: 'svg' },
|
|
31
|
+
{ kind: 'activities', file: 'activities/platform-launch.activities.transitrix.yaml', markup: 'svg' },
|
|
32
|
+
{ kind: 'activity-card', file: 'activity-card/eu-programme.activity-card.transitrix.yaml', markup: 'svg' },
|
|
33
|
+
{ kind: 'process-blueprint', file: 'process-blueprint/order-fulfilment.process-blueprint.transitrix.yaml', markup: 'svg' },
|
|
34
|
+
{ kind: 'blocks', file: 'blocks/architecture.blocks.transitrix.yaml', markup: 'svg' },
|
|
35
|
+
{ kind: 'applications', file: 'applications/portfolio-2026.applications.transitrix.yaml', markup: 'section' },
|
|
36
|
+
{ kind: 'products', file: 'products/portfolio-2026.products.transitrix.yaml', markup: 'section' },
|
|
37
|
+
{ kind: 'process-map', file: 'process-map/enterprise.process-map.transitrix.yaml', markup: 'section' },
|
|
38
|
+
{ kind: 'scenarios', file: 'scenarios/omnichannel-2028.scenarios.transitrix.yaml', markup: 'section' },
|
|
39
|
+
{ kind: 'capability-map', file: 'capability-map/business.capability-map.transitrix.yaml', markup: 'section' },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
describe('webview/entry — Step 4 notation coverage', () => {
|
|
43
|
+
it('wires every supported kind (no kind left on NOTATION-NOT-WIRED)', () => {
|
|
44
|
+
// The fixture table must cover the full supported-kinds surface, so a new
|
|
45
|
+
// kind added to the bundle without a renderer fails this test loudly.
|
|
46
|
+
const covered = new Set(FIXTURES.map((f) => f.kind));
|
|
47
|
+
for (const kind of api.supportedKinds) {
|
|
48
|
+
expect(covered.has(kind)).toBe(true);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
for (const fx of FIXTURES) {
|
|
53
|
+
it(`renders ${fx.kind} from its example fixture`, () => {
|
|
54
|
+
const source = readFileSync(path.join(EXAMPLES, fx.file), 'utf8');
|
|
55
|
+
const r = render(fx.kind, source);
|
|
56
|
+
expect(r.notation).toBe(fx.kind);
|
|
57
|
+
expect(r.errors).toEqual([]);
|
|
58
|
+
expect(r.status).toBe('ok');
|
|
59
|
+
expect(r.svg.length).toBeGreaterThan(0);
|
|
60
|
+
expect(r.svg).toContain(fx.markup === 'svg' ? '<svg ' : '<section');
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
it('degrades malformed input to the error panel for a diagram notation', () => {
|
|
65
|
+
const r = render('process-blueprint', 'process_blueprint:\n stages: "not a list"\n');
|
|
66
|
+
expect(r.status).toBe('error');
|
|
67
|
+
expect(r.errors.length).toBeGreaterThan(0);
|
|
68
|
+
expect(r.svg).toBe('');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('degrades malformed input to the error panel for a catalogue notation', () => {
|
|
72
|
+
const r = render('applications', 'applications_catalogue:\n applications: "not a list"\n');
|
|
73
|
+
expect(r.status).toBe('error');
|
|
74
|
+
expect(r.errors.length).toBeGreaterThan(0);
|
|
75
|
+
expect(r.svg).toBe('');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { api, render } from '../entry.js';
|
|
4
|
+
|
|
5
|
+
const VALID_GOALS_DOC = `
|
|
6
|
+
notation: goals
|
|
7
|
+
id: GOALS-WEBVIEW-1
|
|
8
|
+
name: "Webview entry smoke test"
|
|
9
|
+
goal_types:
|
|
10
|
+
- { name: "Strategy", level: 0 }
|
|
11
|
+
goals:
|
|
12
|
+
- id: GOAL-MOON-1
|
|
13
|
+
name: "Reach the moon"
|
|
14
|
+
type: "Strategy"
|
|
15
|
+
level: 0
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
describe('webview/entry — Step 2 host API', () => {
|
|
19
|
+
it('exposes a version + supportedKinds + render() trio', () => {
|
|
20
|
+
expect(api.version).toMatch(/^\d+\.\d+\.\d+/);
|
|
21
|
+
expect(api.supportedKinds).toContain('goals');
|
|
22
|
+
expect(typeof api.render).toBe('function');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('parses + validates + renders SVG for a well-formed goals document', () => {
|
|
26
|
+
const r = render('goals', VALID_GOALS_DOC);
|
|
27
|
+
expect(r.notation).toBe('goals');
|
|
28
|
+
expect(r.status).toBe('ok');
|
|
29
|
+
expect(r.errors).toEqual([]);
|
|
30
|
+
// Step 3 wires the goals renderer — SVG must now be non-empty and contain
|
|
31
|
+
// the goal name from the YAML.
|
|
32
|
+
expect(r.svg).toContain('<svg ');
|
|
33
|
+
expect(r.svg).toContain('Reach the moon');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('returns YAML-PARSE on malformed input — no exception escapes to the host', () => {
|
|
37
|
+
const r = render('goals', 'goals:\n - id: g1\n name: [unterminated');
|
|
38
|
+
expect(r.status).toBe('error');
|
|
39
|
+
expect(r.errors[0].code).toBe('YAML-PARSE');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('returns KIND-UNKNOWN for a non-Transitrix notation kind', () => {
|
|
43
|
+
const r = render('plantuml', VALID_GOALS_DOC);
|
|
44
|
+
expect(r.status).toBe('error');
|
|
45
|
+
expect(r.errors[0].code).toBe('KIND-UNKNOWN');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('routes non-goals kinds to their validator after Step 4 (no NOTATION-NOT-WIRED)', () => {
|
|
49
|
+
// Every supported kind is now wired to its validator + renderer. A
|
|
50
|
+
// malformed fgca document must surface a structured validation error from
|
|
51
|
+
// the fgca validator — never the Step-2/3 "not wired" placeholder.
|
|
52
|
+
const r = render('fgca', 'changes: []\n');
|
|
53
|
+
expect(r.status).toBe('error');
|
|
54
|
+
expect(r.errors.length).toBeGreaterThan(0);
|
|
55
|
+
expect(r.errors.every((e) => e.code !== 'NOTATION-NOT-WIRED')).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('surfaces goals validation errors structurally (e.g. missing notation header)', () => {
|
|
59
|
+
const r = render('goals', 'goals: []\n');
|
|
60
|
+
expect(r.status).toBe('error');
|
|
61
|
+
// parseCanonicalGoals emits GOALS-* codes for canonical-shape violations.
|
|
62
|
+
expect(r.errors.some((e) => e.code.startsWith('GOALS-'))).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the host-neutral goals SVG renderer used by the IntelliJ
|
|
3
|
+
* JCEF preview bundle. The IntelliJ build can't run inside Vitest, so these
|
|
4
|
+
* tests are the only place the goals rendering path is exercised on the
|
|
5
|
+
* webview-bundle side of the codebase.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, expect, it } from 'vitest';
|
|
8
|
+
|
|
9
|
+
import type { GoalTree } from '../../goals/types.js';
|
|
10
|
+
import { renderGoalsSvg } from '../render-goals.js';
|
|
11
|
+
|
|
12
|
+
const SIMPLE_TREE: GoalTree = {
|
|
13
|
+
goal_types: [
|
|
14
|
+
{ name: 'Strategy', level: 0 },
|
|
15
|
+
{ name: 'Tactic', level: 1 },
|
|
16
|
+
],
|
|
17
|
+
goals: [
|
|
18
|
+
{ id: 1, name: 'Reach the moon', type: 'Strategy', level: 0, parent_id: 0 },
|
|
19
|
+
{ id: 2, name: 'Build a rocket', type: 'Tactic', level: 1, parent_id: 1 },
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
describe('renderGoalsSvg', () => {
|
|
24
|
+
it('produces a self-contained <svg> with embedded theme CSS', () => {
|
|
25
|
+
const svg = renderGoalsSvg(SIMPLE_TREE, { treeName: 'Apollo' });
|
|
26
|
+
expect(svg.startsWith('<svg ')).toBe(true);
|
|
27
|
+
expect(svg).toContain('xmlns="http://www.w3.org/2000/svg"');
|
|
28
|
+
expect(svg).toContain('<style>');
|
|
29
|
+
// The shared theme CSS contract: diagram classes are defined inline.
|
|
30
|
+
expect(svg).toContain('.diagram-node');
|
|
31
|
+
expect(svg).toContain('.diagram-edge');
|
|
32
|
+
// Both goal names made it into the output.
|
|
33
|
+
expect(svg).toContain('Reach the moon');
|
|
34
|
+
expect(svg).toContain('Build a rocket');
|
|
35
|
+
// The strategy → tactic parent link rendered as an edge with the arrow marker.
|
|
36
|
+
expect(svg).toContain('marker-end="url(#arrow)"');
|
|
37
|
+
// Title block is present when treeName is supplied.
|
|
38
|
+
expect(svg).toContain('Goal tree — Apollo');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('escapes user-controlled strings (XML safety)', () => {
|
|
42
|
+
const tree: GoalTree = {
|
|
43
|
+
goal_types: [{ name: 'Strategy', level: 0 }],
|
|
44
|
+
goals: [
|
|
45
|
+
{
|
|
46
|
+
id: 1,
|
|
47
|
+
name: 'Drop <script>alert(1)</script> & friends',
|
|
48
|
+
type: 'Strategy',
|
|
49
|
+
level: 0,
|
|
50
|
+
parent_id: 0,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
const svg = renderGoalsSvg(tree);
|
|
55
|
+
expect(svg).not.toContain('<script>alert(1)</script>');
|
|
56
|
+
expect(svg).toContain('<script>');
|
|
57
|
+
expect(svg).toContain('&');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('returns an empty SVG when the tree has no goals', () => {
|
|
61
|
+
const empty: GoalTree = { goal_types: [{ name: 'Strategy', level: 0 }], goals: [] };
|
|
62
|
+
const svg = renderGoalsSvg(empty);
|
|
63
|
+
expect(svg).toContain('<svg ');
|
|
64
|
+
expect(svg).toContain('width="0"');
|
|
65
|
+
expect(svg).toContain('height="0"');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('omits the title block when treeName is missing', () => {
|
|
69
|
+
const svg = renderGoalsSvg(SIMPLE_TREE);
|
|
70
|
+
expect(svg).not.toContain('Goal tree —');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-bundle entry point for the IntelliJ JCEF preview surface (and any
|
|
3
|
+
* other host that wants the same in-browser API).
|
|
4
|
+
*
|
|
5
|
+
* Why: ADR 0001 picks JCEF + a bundled `@transitrix/diagrams` over a JVM-side
|
|
6
|
+
* re-implementation. This module is the API contract between the JVM host
|
|
7
|
+
* (which posts raw document text + the notation kind) and the rendering JS
|
|
8
|
+
* (which parses, validates, and — Step 3+ — renders SVG). Centralising the
|
|
9
|
+
* surface in one file means the JVM side only has to know about
|
|
10
|
+
* `window.transitrix.render(kind, source)` regardless of which notation the
|
|
11
|
+
* user opened.
|
|
12
|
+
*
|
|
13
|
+
* Step 2 scope: wire YAML parsing, dispatch to the right validator, surface
|
|
14
|
+
* validation/parse errors in a structured JSON shape.
|
|
15
|
+
* Step 3 scope: wire the `goals` SVG renderer so the bundle returns non-empty
|
|
16
|
+
* `svg` for a valid goals document.
|
|
17
|
+
* Step 4 scope (this PR): wire the remaining eleven notations — each one
|
|
18
|
+
* validates the parsed YAML and, when valid, renders host-neutral markup
|
|
19
|
+
* (SVG for the diagram notations, an HTML fragment for the catalogue
|
|
20
|
+
* notations). The JVM host drops whatever `svg` carries into the DOM, so the
|
|
21
|
+
* field name is historical — it transports any self-contained markup.
|
|
22
|
+
*/
|
|
23
|
+
import yaml from 'js-yaml';
|
|
24
|
+
|
|
25
|
+
import { validateActivities } from '../activities/index.js';
|
|
26
|
+
import type { ActivityDoc } from '../activities/index.js';
|
|
27
|
+
import { validateActivityCard } from '../activity-card/index.js';
|
|
28
|
+
import type { ActivityCardDoc } from '../activity-card/index.js';
|
|
29
|
+
import { validateApplicationsCatalogue } from '../applications/index.js';
|
|
30
|
+
import type { ApplicationsCatalogueFile } from '../applications/index.js';
|
|
31
|
+
import { validateNestedBlocks } from '../blocks/index.js';
|
|
32
|
+
import type { BlocksFile } from '../blocks/index.js';
|
|
33
|
+
import { validateCapabilityMap } from '../capability-map/index.js';
|
|
34
|
+
import type { CapabilityMapFile } from '../capability-map/index.js';
|
|
35
|
+
import { parseCanonicalFGCA, parseCanonicalFGA } from '../fgca/parse-canonical.js';
|
|
36
|
+
import { parseCanonicalGoals } from '../goals/parse-canonical.js';
|
|
37
|
+
import { validateProcessBlueprint } from '../process-blueprint/index.js';
|
|
38
|
+
import type { ProcessBlueprintFile } from '../process-blueprint/index.js';
|
|
39
|
+
import { validateProcessMap } from '../process-map/index.js';
|
|
40
|
+
import type { ProcessMapFile } from '../process-map/index.js';
|
|
41
|
+
import { validateProductsCatalogue } from '../products/index.js';
|
|
42
|
+
import type { ProductsCatalogueFile } from '../products/index.js';
|
|
43
|
+
import { validateScenario } from '../scenarios/index.js';
|
|
44
|
+
import type { ScenarioFile } from '../scenarios/index.js';
|
|
45
|
+
import { coerceDatesToIsoStrings } from '../yaml-normalize.js';
|
|
46
|
+
|
|
47
|
+
import { renderActivitiesSvg } from './render-activities.js';
|
|
48
|
+
import { renderActivityCardSvg } from './render-activity-card.js';
|
|
49
|
+
import { renderApplicationsHtml } from './render-applications.js';
|
|
50
|
+
import { renderBlocksSvg } from './render-blocks.js';
|
|
51
|
+
import { renderCapabilityMapHtml } from './render-capability-map.js';
|
|
52
|
+
import { renderFgcaSvg } from './render-fgca.js';
|
|
53
|
+
import { renderGoalsSvg } from './render-goals.js';
|
|
54
|
+
import { renderProcessBlueprintSvg } from './render-process-blueprint.js';
|
|
55
|
+
import { renderProcessMapHtml } from './render-process-map.js';
|
|
56
|
+
import { renderProductsHtml } from './render-products.js';
|
|
57
|
+
import { renderScenarioHtml } from './render-scenarios.js';
|
|
58
|
+
|
|
59
|
+
export interface RenderError {
|
|
60
|
+
code: string;
|
|
61
|
+
message: string;
|
|
62
|
+
path?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface RenderWarning {
|
|
66
|
+
code: string;
|
|
67
|
+
message: string;
|
|
68
|
+
path?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type RenderStatus = 'ok' | 'error';
|
|
72
|
+
|
|
73
|
+
export interface RenderResult {
|
|
74
|
+
status: RenderStatus;
|
|
75
|
+
notation: string;
|
|
76
|
+
/**
|
|
77
|
+
* Self-contained markup for the rendered notation — an `<svg>` for the
|
|
78
|
+
* diagram notations, an HTML `<section>` for the catalogue notations. Empty
|
|
79
|
+
* on validation failure (the host shows the error panel instead). The field
|
|
80
|
+
* name is historical; the JVM host injects whatever it carries into the DOM.
|
|
81
|
+
*/
|
|
82
|
+
svg: string;
|
|
83
|
+
errors: RenderError[];
|
|
84
|
+
warnings: RenderWarning[];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Notation kinds the host can request. Mirrors the `*.<kind>.<…>` suffix
|
|
89
|
+
* convention used by the VS Code extension's `activationEvents`. All twelve
|
|
90
|
+
* are wired to their validator + renderer as of Step 4.
|
|
91
|
+
*/
|
|
92
|
+
export type NotationKind =
|
|
93
|
+
| 'goals'
|
|
94
|
+
| 'fgca'
|
|
95
|
+
| 'fga'
|
|
96
|
+
| 'activities'
|
|
97
|
+
| 'activity-card'
|
|
98
|
+
| 'applications'
|
|
99
|
+
| 'products'
|
|
100
|
+
| 'process-map'
|
|
101
|
+
| 'process-blueprint'
|
|
102
|
+
| 'scenarios'
|
|
103
|
+
| 'capability-map'
|
|
104
|
+
| 'blocks';
|
|
105
|
+
|
|
106
|
+
const SUPPORTED_KINDS: readonly NotationKind[] = [
|
|
107
|
+
'goals',
|
|
108
|
+
'fgca',
|
|
109
|
+
'fga',
|
|
110
|
+
'activities',
|
|
111
|
+
'activity-card',
|
|
112
|
+
'applications',
|
|
113
|
+
'products',
|
|
114
|
+
'process-map',
|
|
115
|
+
'process-blueprint',
|
|
116
|
+
'scenarios',
|
|
117
|
+
'capability-map',
|
|
118
|
+
'blocks',
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
const VERSION = '0.1.0';
|
|
122
|
+
|
|
123
|
+
function emptyResult(notation: string, status: RenderStatus): RenderResult {
|
|
124
|
+
return { status, notation, svg: '', errors: [], warnings: [] };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function errorResult(notation: string, code: string, message: string, path?: string): RenderResult {
|
|
128
|
+
const r = emptyResult(notation, 'error');
|
|
129
|
+
r.errors.push(path !== undefined ? { code, message, path } : { code, message });
|
|
130
|
+
return r;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function parseYaml(source: string): { doc?: unknown; error?: string } {
|
|
134
|
+
try {
|
|
135
|
+
// Coerce native `Date`s (bare `2026-06-01` per YAML 1.1) back to ISO
|
|
136
|
+
// strings before validation — every notation validator expects string
|
|
137
|
+
// dates, and the VS Code previews apply the same normalisation. Without
|
|
138
|
+
// it the canonical-minus-quotes form would falsely fail shape checks.
|
|
139
|
+
return { doc: coerceDatesToIsoStrings(yaml.load(source)) };
|
|
140
|
+
} catch (e: unknown) {
|
|
141
|
+
return { error: e instanceof Error ? e.message : String(e) };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
interface ValidationLike {
|
|
146
|
+
valid: boolean;
|
|
147
|
+
errors: RenderError[];
|
|
148
|
+
warnings: RenderWarning[];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Shared shape for the validate-then-render notations: copy the validator's
|
|
153
|
+
* errors/warnings into the result, and render markup only once the document is
|
|
154
|
+
* valid. `renderMarkup` is a thunk so the (type-asserted) render call never
|
|
155
|
+
* runs against a document the validator rejected.
|
|
156
|
+
*/
|
|
157
|
+
function renderFromValidation(
|
|
158
|
+
kind: NotationKind,
|
|
159
|
+
result: ValidationLike,
|
|
160
|
+
renderMarkup: () => string,
|
|
161
|
+
): RenderResult {
|
|
162
|
+
const r = emptyResult(kind, result.valid ? 'ok' : 'error');
|
|
163
|
+
r.errors.push(...result.errors);
|
|
164
|
+
r.warnings.push(...result.warnings);
|
|
165
|
+
if (result.valid) {
|
|
166
|
+
r.svg = renderMarkup();
|
|
167
|
+
}
|
|
168
|
+
return r;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function dispatchValidate(kind: NotationKind, doc: unknown): RenderResult {
|
|
172
|
+
switch (kind) {
|
|
173
|
+
case 'goals': {
|
|
174
|
+
const v = parseCanonicalGoals(doc);
|
|
175
|
+
const r = emptyResult('goals', v.valid ? 'ok' : 'error');
|
|
176
|
+
r.errors.push(...v.errors);
|
|
177
|
+
r.warnings.push(...v.warnings);
|
|
178
|
+
if (v.valid && v.parsed) {
|
|
179
|
+
const meta = (doc ?? {}) as { name?: unknown };
|
|
180
|
+
const treeName = typeof meta.name === 'string' ? meta.name : '';
|
|
181
|
+
r.svg = renderGoalsSvg(v.parsed, { treeName });
|
|
182
|
+
}
|
|
183
|
+
return r;
|
|
184
|
+
}
|
|
185
|
+
// FGCA and FGA share the canonical parse + renderer; only the layer
|
|
186
|
+
// visibility differs (FGA collapses the Change column). Both carry the
|
|
187
|
+
// parsed `FGCADoc` on the result's `parsed` field when valid.
|
|
188
|
+
case 'fgca': {
|
|
189
|
+
const v = parseCanonicalFGCA(doc);
|
|
190
|
+
const r = emptyResult('fgca', v.valid ? 'ok' : 'error');
|
|
191
|
+
r.errors.push(...v.errors);
|
|
192
|
+
r.warnings.push(...v.warnings);
|
|
193
|
+
if (v.valid && v.parsed) {
|
|
194
|
+
r.svg = renderFgcaSvg(v.parsed, { variant: 'fgca' });
|
|
195
|
+
}
|
|
196
|
+
return r;
|
|
197
|
+
}
|
|
198
|
+
case 'fga': {
|
|
199
|
+
const v = parseCanonicalFGA(doc);
|
|
200
|
+
const r = emptyResult('fga', v.valid ? 'ok' : 'error');
|
|
201
|
+
r.errors.push(...v.errors);
|
|
202
|
+
r.warnings.push(...v.warnings);
|
|
203
|
+
if (v.valid && v.parsed) {
|
|
204
|
+
r.svg = renderFgcaSvg(v.parsed, { variant: 'fga' });
|
|
205
|
+
}
|
|
206
|
+
return r;
|
|
207
|
+
}
|
|
208
|
+
case 'activities':
|
|
209
|
+
return renderFromValidation('activities', validateActivities(doc), () =>
|
|
210
|
+
renderActivitiesSvg(doc as ActivityDoc),
|
|
211
|
+
);
|
|
212
|
+
case 'activity-card':
|
|
213
|
+
return renderFromValidation('activity-card', validateActivityCard(doc), () =>
|
|
214
|
+
renderActivityCardSvg(doc as ActivityCardDoc),
|
|
215
|
+
);
|
|
216
|
+
case 'process-blueprint':
|
|
217
|
+
return renderFromValidation('process-blueprint', validateProcessBlueprint(doc), () =>
|
|
218
|
+
renderProcessBlueprintSvg(doc as ProcessBlueprintFile),
|
|
219
|
+
);
|
|
220
|
+
case 'blocks':
|
|
221
|
+
return renderFromValidation('blocks', validateNestedBlocks(doc), () =>
|
|
222
|
+
renderBlocksSvg(doc as BlocksFile),
|
|
223
|
+
);
|
|
224
|
+
// Catalogue notations render an HTML fragment from the header nested under
|
|
225
|
+
// their top-level wrapper key (`<thing>_catalogue` / `scenario` / …).
|
|
226
|
+
case 'applications':
|
|
227
|
+
return renderFromValidation('applications', validateApplicationsCatalogue(doc), () =>
|
|
228
|
+
renderApplicationsHtml((doc as ApplicationsCatalogueFile).applications_catalogue),
|
|
229
|
+
);
|
|
230
|
+
case 'products':
|
|
231
|
+
return renderFromValidation('products', validateProductsCatalogue(doc), () =>
|
|
232
|
+
renderProductsHtml((doc as ProductsCatalogueFile).products_catalogue),
|
|
233
|
+
);
|
|
234
|
+
case 'process-map':
|
|
235
|
+
return renderFromValidation('process-map', validateProcessMap(doc), () =>
|
|
236
|
+
renderProcessMapHtml((doc as ProcessMapFile).process_map),
|
|
237
|
+
);
|
|
238
|
+
case 'scenarios':
|
|
239
|
+
return renderFromValidation('scenarios', validateScenario(doc), () =>
|
|
240
|
+
renderScenarioHtml((doc as ScenarioFile).scenario),
|
|
241
|
+
);
|
|
242
|
+
case 'capability-map':
|
|
243
|
+
return renderFromValidation('capability-map', validateCapabilityMap(doc), () =>
|
|
244
|
+
renderCapabilityMapHtml((doc as CapabilityMapFile).capability_map),
|
|
245
|
+
);
|
|
246
|
+
default:
|
|
247
|
+
return errorResult(
|
|
248
|
+
kind,
|
|
249
|
+
'NOTATION-NOT-WIRED',
|
|
250
|
+
`Notation '${kind}' is not wired into the IntelliJ bundle yet.`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function render(notationKind: string, source: string): RenderResult {
|
|
256
|
+
if (typeof notationKind !== 'string' || notationKind.length === 0) {
|
|
257
|
+
return errorResult('', 'KIND-MISSING', 'notationKind is required');
|
|
258
|
+
}
|
|
259
|
+
if (typeof source !== 'string') {
|
|
260
|
+
return errorResult(notationKind, 'SOURCE-INVALID', 'source must be a string');
|
|
261
|
+
}
|
|
262
|
+
if (!SUPPORTED_KINDS.includes(notationKind as NotationKind)) {
|
|
263
|
+
return errorResult(
|
|
264
|
+
notationKind,
|
|
265
|
+
'KIND-UNKNOWN',
|
|
266
|
+
`Unknown notation kind: '${notationKind}'. Expected one of: ${SUPPORTED_KINDS.join(', ')}.`,
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
const parsed = parseYaml(source);
|
|
270
|
+
if (parsed.error !== undefined) {
|
|
271
|
+
return errorResult(notationKind, 'YAML-PARSE', parsed.error);
|
|
272
|
+
}
|
|
273
|
+
return dispatchValidate(notationKind as NotationKind, parsed.doc);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export const api = {
|
|
277
|
+
version: VERSION,
|
|
278
|
+
supportedKinds: SUPPORTED_KINDS,
|
|
279
|
+
render,
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export type TransitrixWebviewApi = typeof api;
|
|
283
|
+
|
|
284
|
+
// Install the API on `window.transitrix` when running in a browser-ish host
|
|
285
|
+
// (JCEF qualifies). In a Node/Vitest context `window` is undefined and the
|
|
286
|
+
// install is a no-op — the named exports remain available for unit tests.
|
|
287
|
+
declare const window: { transitrix?: TransitrixWebviewApi } | undefined;
|
|
288
|
+
if (typeof window !== 'undefined') {
|
|
289
|
+
(window as { transitrix?: TransitrixWebviewApi }).transitrix = api;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export default api;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-safe SVG renderer for the Activities notation (network / PSND view).
|
|
3
|
+
*
|
|
4
|
+
* Step 4 of the IntelliJ epic (ADR 0001): the webview bundle must turn a
|
|
5
|
+
* validated ActivityDoc into renderable SVG so JCEF can drop it into the
|
|
6
|
+
* preview panel. The VS Code path lives in `extension/src/activities-preview.ts`
|
|
7
|
+
* and pulls in VS Code-specific concerns (themes, title block, Gantt tab
|
|
8
|
+
* switcher, save dialogs); this module is the host-neutral subset — pure
|
|
9
|
+
* layout → SVG with no VS Code APIs, no `node:fs`, no `node:path`.
|
|
10
|
+
*
|
|
11
|
+
* Only the DEFAULT network view (Project Schedule Network Diagram) is ported.
|
|
12
|
+
* The Gantt view, the CSS-only tab switcher and the interactive spacing /
|
|
13
|
+
* curvature controls stay in the VS Code preview.
|
|
14
|
+
*/
|
|
15
|
+
import { layoutActivities } from '../activities/layout.js';
|
|
16
|
+
import { computeCpm } from '../activities/cpm.js';
|
|
17
|
+
import type {
|
|
18
|
+
ActivityDoc,
|
|
19
|
+
ActivitiesLayout,
|
|
20
|
+
ActivitiesLayoutOptions,
|
|
21
|
+
} from '../activities/types.js';
|
|
22
|
+
import { horizontalCubicEdgePath, DEFAULT_EDGE_CURVATURE } from '../edge-path.js';
|
|
23
|
+
import { generateSvgEmbedCss } from '../theme/index.js';
|
|
24
|
+
import { escXml } from './render-util.js';
|
|
25
|
+
|
|
26
|
+
const N_NODE_W = 200;
|
|
27
|
+
const N_NODE_H = 80;
|
|
28
|
+
const N_PAD = 24;
|
|
29
|
+
|
|
30
|
+
// Activities-specific diagram CSS. Mirrors `ACTIVITIES_DIAGRAM_CSS` from the
|
|
31
|
+
// VS Code preview — the rules that shape the network diagram itself (critical
|
|
32
|
+
// path, milestones, edge colours). Embedded alongside the shared theme CSS so
|
|
33
|
+
// the SVG is self-contained for the JCEF host.
|
|
34
|
+
const ACTIVITIES_DIAGRAM_CSS = `
|
|
35
|
+
.act-node { fill: var(--ts-bg-surface, #f8fafc); stroke: var(--ts-border, #94a3b8); stroke-width: 1.5; }
|
|
36
|
+
.critical-node { fill: #fff7ed; stroke: var(--ts-brand-orange, #ff4d00); stroke-width: 2.5; }
|
|
37
|
+
.milestone-node { fill: #ecfeff; stroke: var(--ts-text-muted, #64748b); stroke-dasharray: 4 2; }
|
|
38
|
+
.critical-edge { stroke: var(--ts-brand-orange, #ff4d00); stroke-width: 2; }
|
|
39
|
+
.arrow-fill-critical { fill: var(--ts-brand-orange, #ff4d00); }
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
function truncate(s: string, maxLen: number): string {
|
|
43
|
+
return s.length > maxLen ? s.slice(0, maxLen - 1) + '…' : s;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface RenderActivitiesOptions {
|
|
47
|
+
/** Optional heading rendered as a `text-header` above the diagram. */
|
|
48
|
+
title?: string;
|
|
49
|
+
/** Network column / row gaps. Defaults match `layoutActivities`. */
|
|
50
|
+
gaps?: ActivitiesLayoutOptions;
|
|
51
|
+
/** Edge curvature; 1 = default, 0 = straight, higher = stronger arc. */
|
|
52
|
+
curvature?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Render the network (PSND) view of an already-validated ActivityDoc to a
|
|
57
|
+
* self-contained SVG string.
|
|
58
|
+
*
|
|
59
|
+
* The caller passes a doc cast from the yaml-parsed `unknown` after
|
|
60
|
+
* `validateActivities` returns valid (the activities module has no parsed
|
|
61
|
+
* field, so the dispatcher does `doc as ActivityDoc`).
|
|
62
|
+
*
|
|
63
|
+
* Cyclic graphs degrade gracefully: `layoutActivities` / `computeCpm` defend
|
|
64
|
+
* against cycles internally (Kahn's topo-order omits cyclic nodes from the
|
|
65
|
+
* critical-path computation, which `computeCpm` backfills with neutral CPM
|
|
66
|
+
* values), so this renderer simply renders whatever the layout returns rather
|
|
67
|
+
* than short-circuiting.
|
|
68
|
+
*/
|
|
69
|
+
export function renderActivitiesSvg(doc: ActivityDoc, options: RenderActivitiesOptions = {}): string {
|
|
70
|
+
const { title = '', gaps = {}, curvature = DEFAULT_EDGE_CURVATURE } = options;
|
|
71
|
+
|
|
72
|
+
const layout: ActivitiesLayout = layoutActivities(doc, gaps);
|
|
73
|
+
|
|
74
|
+
if (layout.nodes.length === 0) {
|
|
75
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" viewBox="0 0 0 0"></svg>`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const cpm = computeCpm(doc.activities ?? []);
|
|
79
|
+
const titleH = title ? 24 : 0;
|
|
80
|
+
const w = layout.bounds.width + N_PAD * 2;
|
|
81
|
+
const h = layout.bounds.height + N_PAD * 2 + titleH;
|
|
82
|
+
const ox = -layout.bounds.x + N_PAD;
|
|
83
|
+
const oy = -layout.bounds.y + N_PAD + titleH;
|
|
84
|
+
|
|
85
|
+
const nodeMap = new Map(layout.nodes.map((n) => [n.id, n]));
|
|
86
|
+
|
|
87
|
+
// SVG paints later siblings over earlier ones. Sort non-critical first so the
|
|
88
|
+
// bright orange critical-path edges land on top — a gray edge crossing an
|
|
89
|
+
// orange one shouldn't bury the critical signal.
|
|
90
|
+
const orderedEdges = [...layout.edges].sort(
|
|
91
|
+
(a, b) => Number(Boolean(a.isCritical)) - Number(Boolean(b.isCritical)),
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// Edge path = a single cubic Bézier with horizontal control handles (shared
|
|
95
|
+
// geometry in `edge-path.js`), so the curve meets the vertical node edge at a
|
|
96
|
+
// right angle and the marker-end arrow reads as perpendicular.
|
|
97
|
+
const edgeSvg = orderedEdges
|
|
98
|
+
.map((e) => {
|
|
99
|
+
const s = nodeMap.get(e.sourceId);
|
|
100
|
+
const t = nodeMap.get(e.targetId);
|
|
101
|
+
if (!s || !t) return '';
|
|
102
|
+
const sx = s.x + ox + s.width;
|
|
103
|
+
const sy = s.y + oy + s.height / 2;
|
|
104
|
+
const tx = t.x + ox;
|
|
105
|
+
const ty = t.y + oy + t.height / 2;
|
|
106
|
+
const cls = e.isCritical ? 'diagram-edge critical-edge' : 'diagram-edge';
|
|
107
|
+
const marker = `url(#${e.isCritical ? 'arrow-crit' : 'arrow'})`;
|
|
108
|
+
return `<path d="${horizontalCubicEdgePath(sx, sy, tx, ty, curvature)}" class="${cls}" marker-end="${marker}"/>`;
|
|
109
|
+
})
|
|
110
|
+
.join('\n');
|
|
111
|
+
|
|
112
|
+
const nodeSvg = layout.nodes
|
|
113
|
+
.map((n) => {
|
|
114
|
+
const x = n.x + ox;
|
|
115
|
+
const y = n.y + oy;
|
|
116
|
+
const isCritical = cpm.get(n.id)?.isCritical ?? false;
|
|
117
|
+
const isMilestone = (n.data.duration ?? -1) === 0;
|
|
118
|
+
const cls = `diagram-node act-node ${isCritical ? 'critical-node' : ''} ${isMilestone ? 'milestone-node' : ''}`.trim();
|
|
119
|
+
const idLabel = escXml(n.id);
|
|
120
|
+
const nameLabel = escXml(truncate(n.data.name, 24));
|
|
121
|
+
const durLabel = n.data.duration !== undefined ? `${n.data.duration}d` : '—';
|
|
122
|
+
return [
|
|
123
|
+
`<rect class="${cls}" x="${x}" y="${y}" width="${N_NODE_W}" height="${N_NODE_H}" rx="6"/>`,
|
|
124
|
+
`<text class="text-id" x="${x + 8}" y="${y + 18}">${idLabel}</text>`,
|
|
125
|
+
`<text class="text-primary" x="${x + N_NODE_W / 2}" y="${y + N_NODE_H / 2}" text-anchor="middle" dominant-baseline="central">${nameLabel}</text>`,
|
|
126
|
+
`<text class="text-secondary" x="${x + N_NODE_W - 8}" y="${y + N_NODE_H - 10}" text-anchor="end">${escXml(durLabel)}</text>`,
|
|
127
|
+
].join('\n');
|
|
128
|
+
})
|
|
129
|
+
.join('\n');
|
|
130
|
+
|
|
131
|
+
const titleSvg = title
|
|
132
|
+
? `<text class="text-header" x="${N_PAD}" y="${N_PAD - 6}">${escXml(title)}</text>`
|
|
133
|
+
: '';
|
|
134
|
+
|
|
135
|
+
// Embed the shared theme CSS plus the activities-specific diagram CSS inside
|
|
136
|
+
// the SVG so the rendered output is self-contained — the JCEF host page only
|
|
137
|
+
// needs to drop the SVG into the DOM and styling resolves without any
|
|
138
|
+
// cooperation from the host stylesheet. Matches what the VS Code path
|
|
139
|
+
// produces via `prepareSvgForExport`.
|
|
140
|
+
const embedCss = generateSvgEmbedCss('transitrix') + ACTIVITIES_DIAGRAM_CSS;
|
|
141
|
+
|
|
142
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">
|
|
143
|
+
<style>${embedCss}</style>
|
|
144
|
+
<defs>
|
|
145
|
+
<marker id="arrow" markerWidth="8" markerHeight="8" refX="8" refY="3" orient="auto">
|
|
146
|
+
<path d="M0,0 L0,6 L8,3 z" class="arrow-fill"/>
|
|
147
|
+
</marker>
|
|
148
|
+
<marker id="arrow-crit" markerWidth="8" markerHeight="8" refX="8" refY="3" orient="auto">
|
|
149
|
+
<path d="M0,0 L0,6 L8,3 z" class="arrow-fill-critical"/>
|
|
150
|
+
</marker>
|
|
151
|
+
</defs>
|
|
152
|
+
${titleSvg}
|
|
153
|
+
${nodeSvg}
|
|
154
|
+
${edgeSvg}
|
|
155
|
+
</svg>`;
|
|
156
|
+
}
|