yarramate 0.11.0 → 0.12.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.
@@ -712,6 +712,9 @@ export function runLikeC4Cli(args, cwd = process.cwd()) {
712
712
  ? [
713
713
  {
714
714
  ...(view.id === undefined ? {} : { id: view.id }),
715
+ ...(view.folder === undefined
716
+ ? {}
717
+ : { folder: view.folder }),
715
718
  prepared,
716
719
  ...(view.compare === undefined
717
720
  ? {}
@@ -11,6 +11,7 @@ export interface LikeC4ProjectDefinition {
11
11
  readonly views: ReadonlyArray<{
12
12
  readonly id?: string;
13
13
  readonly projection: string;
14
+ readonly folder?: string;
14
15
  readonly compare?: {
15
16
  readonly from: string;
16
17
  readonly to: string;
@@ -40,6 +41,7 @@ export interface LikeC4Deployment {
40
41
  export declare const loadLikeC4ProjectDefinition: (source: WorkspaceSource) => import("../source-document.js").SourceDocumentResult<LikeC4ProjectDefinition>;
41
42
  export interface PreparedLikeC4ProjectView {
42
43
  readonly id?: string;
44
+ readonly folder?: string;
43
45
  readonly prepared: Extract<LikeC4PreparationResult, {
44
46
  readonly ok: true;
45
47
  }>;
@@ -8,6 +8,15 @@ const Ajv2020 = Ajv2020Module.default;
8
8
  const validateLikeC4Project = new Ajv2020({ allErrors: true }).compile(likeC4ProjectSchema);
9
9
  export const loadLikeC4ProjectDefinition = (source) => loadSourceDocument(source, validateLikeC4Project, 'LikeC4 project');
10
10
  const quote = (value) => `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'").replaceAll('\n', '\\n')}'`;
11
+ // A folder files the view in LikeC4's sidebar tree: the title becomes a
12
+ // path ('Folder / Title') whose last segment is the displayed title (ADR
13
+ // 0067). A view without a declared title still needs a title line to
14
+ // carry the path, so the view id stands in as the leaf.
15
+ const titleLines = (folder, title, viewId) => folder === undefined
16
+ ? title === undefined
17
+ ? []
18
+ : [` title ${quote(title)}`]
19
+ : [` title ${quote(`${folder} / ${title ?? viewId}`)}`];
11
20
  const unionProjection = (project, views) => ({
12
21
  format: 'yarramate/projection-result/v1',
13
22
  projection: `${project.id}@${project.version}`,
@@ -28,7 +37,7 @@ const unionProjection = (project, views) => ({
28
37
  ...new Map(views.flatMap(({ prepared }) => prepared.projection.claims.map((claim) => [claim.id, claim]))).values(),
29
38
  ].sort((left, right) => left.id.localeCompare(right.id)),
30
39
  });
31
- const viewBody = ({ id, prepared, dynamic, deployment, }, gitChange) => {
40
+ const viewBody = ({ id, folder, prepared, dynamic, deployment, }, gitChange) => {
32
41
  const source = prepared.source;
33
42
  const startToken = '\nviews {\n';
34
43
  const start = source.indexOf(startToken);
@@ -58,9 +67,7 @@ const viewBody = ({ id, prepared, dynamic, deployment, }, gitChange) => {
58
67
  const viewId = id ?? prepared.projection.projection.split('@')[0];
59
68
  return [
60
69
  ` deployment view ${viewId} {`,
61
- ...(prepared.projection.presentation?.title === undefined
62
- ? []
63
- : [` title ${quote(prepared.projection.presentation.title)}`]),
70
+ ...titleLines(folder, prepared.projection.presentation?.title, viewId),
64
71
  ...(prepared.projection.presentation?.description === undefined
65
72
  ? []
66
73
  : [
@@ -105,9 +112,7 @@ const viewBody = ({ id, prepared, dynamic, deployment, }, gitChange) => {
105
112
  const viewId = id ?? prepared.projection.projection.split('@')[0];
106
113
  return [
107
114
  ` dynamic view ${viewId} {`,
108
- ...(prepared.projection.presentation?.title === undefined
109
- ? []
110
- : [` title ${quote(prepared.projection.presentation.title)}`]),
115
+ ...titleLines(folder, prepared.projection.presentation?.title, viewId),
111
116
  ...(prepared.projection.presentation?.description === undefined
112
117
  ? []
113
118
  : [
@@ -140,10 +145,17 @@ const viewBody = ({ id, prepared, dynamic, deployment, }, gitChange) => {
140
145
  ...relationshipRules,
141
146
  ...overlayRules,
142
147
  ].join('\n');
143
- return source
148
+ const viewId = id ?? prepared.projection.projection.split('@')[0];
149
+ const body = source
144
150
  .slice(start + startToken.length, end)
145
- .replace(/^ view [A-Za-z_][A-Za-z0-9_-]* \{/, ` view ${id ?? prepared.projection.projection.split('@')[0]} {`)
151
+ .replace(/^ view [A-Za-z_][A-Za-z0-9_-]* \{/, ` view ${viewId} {`)
146
152
  .replace(' include *', membershipRules);
153
+ if (folder === undefined)
154
+ return body;
155
+ const title = prepared.projection.presentation?.title;
156
+ return title === undefined
157
+ ? body.replace(` view ${viewId} {`, ` view ${viewId} {\n${titleLines(folder, undefined, viewId).join('\n')}`)
158
+ : body.replace(` title ${quote(title)}`, titleLines(folder, title, viewId).join('\n'));
147
159
  };
148
160
  const deploymentBody = ({ deployment, prepared, }) => {
149
161
  if (deployment === undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yarramate",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Tool-neutral semantic architecture engine and guided methodology",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -72,6 +72,11 @@
72
72
  "projection": {
73
73
  "$ref": "#/$defs/path"
74
74
  },
75
+ "folder": {
76
+ "type": "string",
77
+ "description": "Sidebar folder for the rendered view, emitted as a LikeC4 title path ('Folder / Title'). Nest with '/' separators; folders appear in the order their first view appears in the views list.",
78
+ "pattern": "^[^/]+(?:/[^/]+)*$"
79
+ },
75
80
  "compare": {
76
81
  "$ref": "#/$defs/comparison"
77
82
  },