obsidian-accomplishments-mcp 0.1.10 → 0.1.12
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/README.md +156 -184
- package/dist/index.js +207 -38
- package/dist/index.js.map +1 -1
- package/dist/integration.test.d.ts +8 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +979 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/models/types.d.ts +1 -2
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js.map +1 -1
- package/dist/models/v2-types.d.ts +460 -0
- package/dist/models/v2-types.d.ts.map +1 -0
- package/dist/models/v2-types.js +137 -0
- package/dist/models/v2-types.js.map +1 -0
- package/dist/models/v2-types.test.d.ts +5 -0
- package/dist/models/v2-types.test.d.ts.map +1 -0
- package/dist/models/v2-types.test.js +133 -0
- package/dist/models/v2-types.test.js.map +1 -0
- package/dist/parsers/canvas-parser.d.ts +1 -1
- package/dist/parsers/canvas-parser.d.ts.map +1 -1
- package/dist/parsers/canvas-parser.js +1 -1
- package/dist/parsers/canvas-parser.js.map +1 -1
- package/dist/parsers/markdown-parser.js +9 -9
- package/dist/parsers/markdown-parser.js.map +1 -1
- package/dist/services/v2/archive-manager.d.ts +96 -0
- package/dist/services/v2/archive-manager.d.ts.map +1 -0
- package/dist/services/v2/archive-manager.js +281 -0
- package/dist/services/v2/archive-manager.js.map +1 -0
- package/dist/services/v2/canvas-manager.d.ts +155 -0
- package/dist/services/v2/canvas-manager.d.ts.map +1 -0
- package/dist/services/v2/canvas-manager.js +540 -0
- package/dist/services/v2/canvas-manager.js.map +1 -0
- package/dist/services/v2/canvas-manager.test.d.ts +5 -0
- package/dist/services/v2/canvas-manager.test.d.ts.map +1 -0
- package/dist/services/v2/canvas-manager.test.js +327 -0
- package/dist/services/v2/canvas-manager.test.js.map +1 -0
- package/dist/services/v2/cascade-manager.d.ts +54 -0
- package/dist/services/v2/cascade-manager.d.ts.map +1 -0
- package/dist/services/v2/cascade-manager.js +220 -0
- package/dist/services/v2/cascade-manager.js.map +1 -0
- package/dist/services/v2/cycle-detector.d.ts +76 -0
- package/dist/services/v2/cycle-detector.d.ts.map +1 -0
- package/dist/services/v2/cycle-detector.js +183 -0
- package/dist/services/v2/cycle-detector.js.map +1 -0
- package/dist/services/v2/cycle-detector.test.d.ts +7 -0
- package/dist/services/v2/cycle-detector.test.d.ts.map +1 -0
- package/dist/services/v2/cycle-detector.test.js +125 -0
- package/dist/services/v2/cycle-detector.test.js.map +1 -0
- package/dist/services/v2/entity-parser.d.ts +54 -0
- package/dist/services/v2/entity-parser.d.ts.map +1 -0
- package/dist/services/v2/entity-parser.js +418 -0
- package/dist/services/v2/entity-parser.js.map +1 -0
- package/dist/services/v2/entity-parser.test.d.ts +5 -0
- package/dist/services/v2/entity-parser.test.d.ts.map +1 -0
- package/dist/services/v2/entity-parser.test.js +637 -0
- package/dist/services/v2/entity-parser.test.js.map +1 -0
- package/dist/services/v2/entity-serializer.d.ts +94 -0
- package/dist/services/v2/entity-serializer.d.ts.map +1 -0
- package/dist/services/v2/entity-serializer.js +583 -0
- package/dist/services/v2/entity-serializer.js.map +1 -0
- package/dist/services/v2/entity-serializer.test.d.ts +5 -0
- package/dist/services/v2/entity-serializer.test.d.ts.map +1 -0
- package/dist/services/v2/entity-serializer.test.js +241 -0
- package/dist/services/v2/entity-serializer.test.js.map +1 -0
- package/dist/services/v2/entity-validator.d.ts +65 -0
- package/dist/services/v2/entity-validator.d.ts.map +1 -0
- package/dist/services/v2/entity-validator.js +573 -0
- package/dist/services/v2/entity-validator.js.map +1 -0
- package/dist/services/v2/entity-validator.test.d.ts +5 -0
- package/dist/services/v2/entity-validator.test.d.ts.map +1 -0
- package/dist/services/v2/entity-validator.test.js +519 -0
- package/dist/services/v2/entity-validator.test.js.map +1 -0
- package/dist/services/v2/file-manager.d.ts +73 -0
- package/dist/services/v2/file-manager.d.ts.map +1 -0
- package/dist/services/v2/file-manager.js +310 -0
- package/dist/services/v2/file-manager.js.map +1 -0
- package/dist/services/v2/file-manager.test.d.ts +5 -0
- package/dist/services/v2/file-manager.test.d.ts.map +1 -0
- package/dist/services/v2/file-manager.test.js +339 -0
- package/dist/services/v2/file-manager.test.js.map +1 -0
- package/dist/services/v2/index-manager.d.ts +68 -0
- package/dist/services/v2/index-manager.d.ts.map +1 -0
- package/dist/services/v2/index-manager.js +228 -0
- package/dist/services/v2/index-manager.js.map +1 -0
- package/dist/services/v2/index-manager.test.d.ts +5 -0
- package/dist/services/v2/index-manager.test.d.ts.map +1 -0
- package/dist/services/v2/index-manager.test.js +386 -0
- package/dist/services/v2/index-manager.test.js.map +1 -0
- package/dist/services/v2/index-service.d.ts +82 -0
- package/dist/services/v2/index-service.d.ts.map +1 -0
- package/dist/services/v2/index-service.js +274 -0
- package/dist/services/v2/index-service.js.map +1 -0
- package/dist/services/v2/index-service.test.d.ts +5 -0
- package/dist/services/v2/index-service.test.d.ts.map +1 -0
- package/dist/services/v2/index-service.test.js +117 -0
- package/dist/services/v2/index-service.test.js.map +1 -0
- package/dist/services/v2/lifecycle-manager.d.ts +59 -0
- package/dist/services/v2/lifecycle-manager.d.ts.map +1 -0
- package/dist/services/v2/lifecycle-manager.js +310 -0
- package/dist/services/v2/lifecycle-manager.js.map +1 -0
- package/dist/services/v2/lifecycle-manager.test.d.ts +5 -0
- package/dist/services/v2/lifecycle-manager.test.d.ts.map +1 -0
- package/dist/services/v2/lifecycle-manager.test.js +141 -0
- package/dist/services/v2/lifecycle-manager.test.js.map +1 -0
- package/dist/services/v2/path-resolver.d.ts +64 -0
- package/dist/services/v2/path-resolver.d.ts.map +1 -0
- package/dist/services/v2/path-resolver.js +174 -0
- package/dist/services/v2/path-resolver.js.map +1 -0
- package/dist/services/v2/progress-computer.d.ts +46 -0
- package/dist/services/v2/progress-computer.d.ts.map +1 -0
- package/dist/services/v2/progress-computer.js +200 -0
- package/dist/services/v2/progress-computer.js.map +1 -0
- package/dist/services/v2/search-service.d.ts +68 -0
- package/dist/services/v2/search-service.d.ts.map +1 -0
- package/dist/services/v2/search-service.js +194 -0
- package/dist/services/v2/search-service.js.map +1 -0
- package/dist/services/v2/transitive-dependency-remover.d.ts +54 -0
- package/dist/services/v2/transitive-dependency-remover.d.ts.map +1 -0
- package/dist/services/v2/transitive-dependency-remover.js +156 -0
- package/dist/services/v2/transitive-dependency-remover.js.map +1 -0
- package/dist/services/v2/transitive-dependency-remover.test.d.ts +7 -0
- package/dist/services/v2/transitive-dependency-remover.test.d.ts.map +1 -0
- package/dist/services/v2/transitive-dependency-remover.test.js +119 -0
- package/dist/services/v2/transitive-dependency-remover.test.js.map +1 -0
- package/dist/services/v2/v2-runtime.d.ts +374 -0
- package/dist/services/v2/v2-runtime.d.ts.map +1 -0
- package/dist/services/v2/v2-runtime.js +1908 -0
- package/dist/services/v2/v2-runtime.js.map +1 -0
- package/dist/services/v2/v2-runtime.test.d.ts +5 -0
- package/dist/services/v2/v2-runtime.test.d.ts.map +1 -0
- package/dist/services/v2/v2-runtime.test.js +658 -0
- package/dist/services/v2/v2-runtime.test.js.map +1 -0
- package/dist/services/v2/workstream-normalizer.d.ts +59 -0
- package/dist/services/v2/workstream-normalizer.d.ts.map +1 -0
- package/dist/services/v2/workstream-normalizer.js +137 -0
- package/dist/services/v2/workstream-normalizer.js.map +1 -0
- package/dist/services/v2/workstream-normalizer.test.d.ts +7 -0
- package/dist/services/v2/workstream-normalizer.test.d.ts.map +1 -0
- package/dist/services/v2/workstream-normalizer.test.js +130 -0
- package/dist/services/v2/workstream-normalizer.test.js.map +1 -0
- package/dist/test-runner.d.ts +4 -1
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +44 -249
- package/dist/test-runner.js.map +1 -1
- package/dist/tools/batch-operations-tools.d.ts +54 -0
- package/dist/tools/batch-operations-tools.d.ts.map +1 -0
- package/dist/tools/batch-operations-tools.js +370 -0
- package/dist/tools/batch-operations-tools.js.map +1 -0
- package/dist/tools/decision-document-tools.d.ts +78 -0
- package/dist/tools/decision-document-tools.d.ts.map +1 -0
- package/dist/tools/decision-document-tools.js +260 -0
- package/dist/tools/decision-document-tools.js.map +1 -0
- package/dist/tools/entity-management-tools.d.ts +79 -0
- package/dist/tools/entity-management-tools.d.ts.map +1 -0
- package/dist/tools/entity-management-tools.js +851 -0
- package/dist/tools/entity-management-tools.js.map +1 -0
- package/dist/tools/entity-management-tools.test.d.ts +5 -0
- package/dist/tools/entity-management-tools.test.d.ts.map +1 -0
- package/dist/tools/entity-management-tools.test.js +530 -0
- package/dist/tools/entity-management-tools.test.js.map +1 -0
- package/dist/tools/index.d.ts +15 -331
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +510 -47
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/index.test.d.ts +8 -0
- package/dist/tools/index.test.d.ts.map +1 -0
- package/dist/tools/index.test.js +429 -0
- package/dist/tools/index.test.js.map +1 -0
- package/dist/tools/project-understanding-tools.d.ts +75 -0
- package/dist/tools/project-understanding-tools.d.ts.map +1 -0
- package/dist/tools/project-understanding-tools.js +751 -0
- package/dist/tools/project-understanding-tools.js.map +1 -0
- package/dist/tools/search-navigation-tools.d.ts +77 -0
- package/dist/tools/search-navigation-tools.d.ts.map +1 -0
- package/dist/tools/search-navigation-tools.js +379 -0
- package/dist/tools/search-navigation-tools.js.map +1 -0
- package/dist/tools/tool-types.d.ts +703 -0
- package/dist/tools/tool-types.d.ts.map +1 -0
- package/dist/tools/tool-types.js +7 -0
- package/dist/tools/tool-types.js.map +1 -0
- package/dist/utils/config.d.ts +0 -4
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +2 -19
- package/dist/utils/config.js.map +1 -1
- package/package.json +16 -1
- package/dist/services/accomplishment-service.d.ts +0 -33
- package/dist/services/accomplishment-service.d.ts.map +0 -1
- package/dist/services/accomplishment-service.js +0 -296
- package/dist/services/accomplishment-service.js.map +0 -1
- package/dist/services/canvas-service.d.ts +0 -96
- package/dist/services/canvas-service.d.ts.map +0 -1
- package/dist/services/canvas-service.js +0 -231
- package/dist/services/canvas-service.js.map +0 -1
- package/dist/services/context-doc-service.d.ts +0 -70
- package/dist/services/context-doc-service.d.ts.map +0 -1
- package/dist/services/context-doc-service.js +0 -229
- package/dist/services/context-doc-service.js.map +0 -1
- package/dist/services/dependency-service.d.ts +0 -22
- package/dist/services/dependency-service.d.ts.map +0 -1
- package/dist/services/dependency-service.js +0 -99
- package/dist/services/dependency-service.js.map +0 -1
- package/dist/services/status-indicator-service.d.ts +0 -40
- package/dist/services/status-indicator-service.d.ts.map +0 -1
- package/dist/services/status-indicator-service.js +0 -173
- package/dist/services/status-indicator-service.js.map +0 -1
- package/dist/services/task-service.d.ts +0 -32
- package/dist/services/task-service.d.ts.map +0 -1
- package/dist/services/task-service.js +0 -152
- package/dist/services/task-service.js.map +0 -1
- package/dist/test-real-vault.d.ts +0 -6
- package/dist/test-real-vault.d.ts.map +0 -1
- package/dist/test-real-vault.js +0 -30
- package/dist/test-real-vault.js.map +0 -1
- package/dist/tools/batch-operations.d.ts +0 -246
- package/dist/tools/batch-operations.d.ts.map +0 -1
- package/dist/tools/batch-operations.js +0 -235
- package/dist/tools/batch-operations.js.map +0 -1
- package/dist/tools/get-accomplishment.d.ts +0 -42
- package/dist/tools/get-accomplishment.d.ts.map +0 -1
- package/dist/tools/get-accomplishment.js +0 -93
- package/dist/tools/get-accomplishment.js.map +0 -1
- package/dist/tools/get-accomplishments-graph.d.ts +0 -26
- package/dist/tools/get-accomplishments-graph.d.ts.map +0 -1
- package/dist/tools/get-accomplishments-graph.js +0 -137
- package/dist/tools/get-accomplishments-graph.js.map +0 -1
- package/dist/tools/get-blocked-items.d.ts +0 -15
- package/dist/tools/get-blocked-items.d.ts.map +0 -1
- package/dist/tools/get-blocked-items.js +0 -73
- package/dist/tools/get-blocked-items.js.map +0 -1
- package/dist/tools/get-current-work.d.ts +0 -15
- package/dist/tools/get-current-work.d.ts.map +0 -1
- package/dist/tools/get-current-work.js +0 -68
- package/dist/tools/get-current-work.js.map +0 -1
- package/dist/tools/get-project-status.d.ts +0 -26
- package/dist/tools/get-project-status.d.ts.map +0 -1
- package/dist/tools/get-project-status.js +0 -98
- package/dist/tools/get-project-status.js.map +0 -1
- package/dist/tools/get-ready-to-start.d.ts +0 -15
- package/dist/tools/get-ready-to-start.d.ts.map +0 -1
- package/dist/tools/get-ready-to-start.js +0 -47
- package/dist/tools/get-ready-to-start.js.map +0 -1
- package/dist/tools/list-accomplishments.d.ts +0 -42
- package/dist/tools/list-accomplishments.d.ts.map +0 -1
- package/dist/tools/list-accomplishments.js +0 -40
- package/dist/tools/list-accomplishments.js.map +0 -1
- package/dist/tools/manage-accomplishment.d.ts +0 -147
- package/dist/tools/manage-accomplishment.d.ts.map +0 -1
- package/dist/tools/manage-accomplishment.js +0 -153
- package/dist/tools/manage-accomplishment.js.map +0 -1
- package/dist/tools/manage-dependency.d.ts +0 -41
- package/dist/tools/manage-dependency.d.ts.map +0 -1
- package/dist/tools/manage-dependency.js +0 -66
- package/dist/tools/manage-dependency.js.map +0 -1
- package/dist/tools/manage-task.d.ts +0 -119
- package/dist/tools/manage-task.d.ts.map +0 -1
- package/dist/tools/manage-task.js +0 -126
- package/dist/tools/manage-task.js.map +0 -1
- package/dist/tools/reconcile-canvas.d.ts +0 -33
- package/dist/tools/reconcile-canvas.d.ts.map +0 -1
- package/dist/tools/reconcile-canvas.js +0 -41
- package/dist/tools/reconcile-canvas.js.map +0 -1
- package/dist/tools/set-work-focus.d.ts +0 -48
- package/dist/tools/set-work-focus.d.ts.map +0 -1
- package/dist/tools/set-work-focus.js +0 -78
- package/dist/tools/set-work-focus.js.map +0 -1
- package/dist/tools/sync-dependencies.d.ts +0 -33
- package/dist/tools/sync-dependencies.d.ts.map +0 -1
- package/dist/tools/sync-dependencies.js +0 -144
- package/dist/tools/sync-dependencies.js.map +0 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V2 Entity Serializer
|
|
3
|
+
*
|
|
4
|
+
* Serializes Entity objects to markdown files with YAML frontmatter.
|
|
5
|
+
*/
|
|
6
|
+
import { Entity } from '../../models/v2-types.js';
|
|
7
|
+
export interface SerializeOptions {
|
|
8
|
+
/** Include content/body section */
|
|
9
|
+
includeContent?: boolean;
|
|
10
|
+
/** Pretty print YAML (default: true) */
|
|
11
|
+
prettyPrint?: boolean;
|
|
12
|
+
/** Fields to exclude from frontmatter */
|
|
13
|
+
excludeFields?: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Serializes Entity objects to markdown with YAML frontmatter.
|
|
17
|
+
*/
|
|
18
|
+
export declare class EntitySerializer {
|
|
19
|
+
/** Serialize an Entity to markdown string */
|
|
20
|
+
serialize(entity: Entity, options?: SerializeOptions): string;
|
|
21
|
+
/** Convert entity to frontmatter object */
|
|
22
|
+
private entityToFrontmatter;
|
|
23
|
+
/** Get base frontmatter fields common to all entities */
|
|
24
|
+
private getBaseFrontmatter;
|
|
25
|
+
/** Get milestone-specific frontmatter */
|
|
26
|
+
private getMilestoneFrontmatter;
|
|
27
|
+
/** Get story-specific frontmatter */
|
|
28
|
+
private getStoryFrontmatter;
|
|
29
|
+
/** Get task-specific frontmatter */
|
|
30
|
+
private getTaskFrontmatter;
|
|
31
|
+
/** Get decision-specific frontmatter */
|
|
32
|
+
private getDecisionFrontmatter;
|
|
33
|
+
/** Get document-specific frontmatter */
|
|
34
|
+
private getDocumentFrontmatter;
|
|
35
|
+
/** Get feature-specific frontmatter */
|
|
36
|
+
private getFeatureFrontmatter;
|
|
37
|
+
/** Get content/body from entity */
|
|
38
|
+
private getEntityContent;
|
|
39
|
+
/** Build milestone content with objective and related queries */
|
|
40
|
+
private buildMilestoneContent;
|
|
41
|
+
/** Build story content with outcome and notes */
|
|
42
|
+
private buildStoryContent;
|
|
43
|
+
/** Build task content with description and notes */
|
|
44
|
+
private buildTaskContent;
|
|
45
|
+
/** Build decision content with context, decision, and rationale */
|
|
46
|
+
private buildDecisionContent;
|
|
47
|
+
/** Build document content */
|
|
48
|
+
private buildDocumentContent;
|
|
49
|
+
/** Build feature content */
|
|
50
|
+
private buildFeatureContent;
|
|
51
|
+
/** Build related section with Dataview queries for milestone/story/task */
|
|
52
|
+
private buildRelatedSection;
|
|
53
|
+
/** Build related section for decisions */
|
|
54
|
+
private buildDecisionRelatedSection;
|
|
55
|
+
/** Build related section for documents */
|
|
56
|
+
private buildDocumentRelatedSection;
|
|
57
|
+
/** Build related section for features */
|
|
58
|
+
private buildFeatureRelatedSection;
|
|
59
|
+
/** Convert object to YAML string */
|
|
60
|
+
private toYaml;
|
|
61
|
+
/** Convert a value to YAML representation */
|
|
62
|
+
private valueToYaml;
|
|
63
|
+
/** Convert array of objects to YAML */
|
|
64
|
+
private arrayOfObjectsToYaml;
|
|
65
|
+
/** Convert object to YAML */
|
|
66
|
+
private objectToYaml;
|
|
67
|
+
/** Check if string needs quoting */
|
|
68
|
+
private needsQuoting;
|
|
69
|
+
/** Escape string for YAML */
|
|
70
|
+
private escapeString;
|
|
71
|
+
/** Serialize inline tasks for frontmatter */
|
|
72
|
+
private serializeInlineTasks;
|
|
73
|
+
/** Remove undefined/null values from object */
|
|
74
|
+
private cleanObject;
|
|
75
|
+
/**
|
|
76
|
+
* Strip dataview blocks and their section headers from content.
|
|
77
|
+
* This prevents duplication when re-serializing entities.
|
|
78
|
+
*
|
|
79
|
+
* Removes:
|
|
80
|
+
* - Dataview code blocks (```dataview ... ```)
|
|
81
|
+
* - Section headers that precede dataview blocks (## 🔗 Implemented By, etc.)
|
|
82
|
+
*/
|
|
83
|
+
private stripDataviewBlocks;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generate CSS classes for visual differentiation on canvas.
|
|
87
|
+
*
|
|
88
|
+
* CSS classes control:
|
|
89
|
+
* - Border thickness: entity type (milestone=4px, story=2px, task=1px)
|
|
90
|
+
* - Border color: workstream type
|
|
91
|
+
* - Visual state: status indicators
|
|
92
|
+
*/
|
|
93
|
+
export declare function generateCssClasses(entity: Entity): string[];
|
|
94
|
+
//# sourceMappingURL=entity-serializer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-serializer.d.ts","sourceRoot":"","sources":["../../../src/services/v2/entity-serializer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,MAAM,EAQP,MAAM,0BAA0B,CAAC;AAMlC,MAAM,WAAW,gBAAgB;IAC/B,mCAAmC;IACnC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wCAAwC;IACxC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yCAAyC;IACzC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAMD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,6CAA6C;IAC7C,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM;IAoBjE,2CAA2C;IAC3C,OAAO,CAAC,mBAAmB;IAoC3B,yDAAyD;IACzD,OAAO,CAAC,kBAAkB;IAe1B,yCAAyC;IACzC,OAAO,CAAC,uBAAuB;IAgB/B,qCAAqC;IACrC,OAAO,CAAC,mBAAmB;IAgB3B,oCAAoC;IACpC,OAAO,CAAC,kBAAkB;IAe1B,wCAAwC;IACxC,OAAO,CAAC,sBAAsB;IAe9B,wCAAwC;IACxC,OAAO,CAAC,sBAAsB;IAkB9B,uCAAuC;IACvC,OAAO,CAAC,qBAAqB;IAkB7B,mCAAmC;IACnC,OAAO,CAAC,gBAAgB;IAiBxB,iEAAiE;IACjE,OAAO,CAAC,qBAAqB;IAa7B,iDAAiD;IACjD,OAAO,CAAC,iBAAiB;IAiBzB,oDAAoD;IACpD,OAAO,CAAC,gBAAgB;IAqBxB,mEAAmE;IACnE,OAAO,CAAC,oBAAoB;IAqB5B,6BAA6B;IAC7B,OAAO,CAAC,oBAAoB;IAiB5B,4BAA4B;IAC5B,OAAO,CAAC,mBAAmB;IAiB3B,2EAA2E;IAC3E,OAAO,CAAC,mBAAmB;IAwC3B,0CAA0C;IAC1C,OAAO,CAAC,2BAA2B;IAmBnC,0CAA0C;IAC1C,OAAO,CAAC,2BAA2B;IAoBnC,yCAAyC;IACzC,OAAO,CAAC,0BAA0B;IAiClC,oCAAoC;IACpC,OAAO,CAAC,MAAM;IAad,6CAA6C;IAC7C,OAAO,CAAC,WAAW;IAqCnB,uCAAuC;IACvC,OAAO,CAAC,oBAAoB;IAoB5B,6BAA6B;IAC7B,OAAO,CAAC,YAAY;IAYpB,oCAAoC;IACpC,OAAO,CAAC,YAAY;IAUpB,6BAA6B;IAC7B,OAAO,CAAC,YAAY;IAYpB,6CAA6C;IAC7C,OAAO,CAAC,oBAAoB;IAW5B,+CAA+C;IAC/C,OAAO,CAAC,WAAW;IAYnB;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;CAqB5B;AAMD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAwB3D"}
|
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V2 Entity Serializer
|
|
3
|
+
*
|
|
4
|
+
* Serializes Entity objects to markdown files with YAML frontmatter.
|
|
5
|
+
*/
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// Entity Serializer Class
|
|
8
|
+
// =============================================================================
|
|
9
|
+
/**
|
|
10
|
+
* Serializes Entity objects to markdown with YAML frontmatter.
|
|
11
|
+
*/
|
|
12
|
+
export class EntitySerializer {
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Main Serialize Method
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/** Serialize an Entity to markdown string */
|
|
17
|
+
serialize(entity, options = {}) {
|
|
18
|
+
const { includeContent = true, excludeFields = [] } = options;
|
|
19
|
+
// Get frontmatter data based on entity type
|
|
20
|
+
const frontmatter = this.entityToFrontmatter(entity, excludeFields);
|
|
21
|
+
// Build YAML frontmatter
|
|
22
|
+
const yaml = this.toYaml(frontmatter);
|
|
23
|
+
// Get content/body
|
|
24
|
+
const content = includeContent ? this.getEntityContent(entity) : '';
|
|
25
|
+
// Combine frontmatter and content
|
|
26
|
+
return `---\n${yaml}---\n${content ? `\n${content}` : ''}`;
|
|
27
|
+
}
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Entity to Frontmatter Conversion
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
/** Convert entity to frontmatter object */
|
|
32
|
+
entityToFrontmatter(entity, excludeFields) {
|
|
33
|
+
const base = this.getBaseFrontmatter(entity);
|
|
34
|
+
let specific;
|
|
35
|
+
switch (entity.type) {
|
|
36
|
+
case 'milestone':
|
|
37
|
+
specific = this.getMilestoneFrontmatter(entity);
|
|
38
|
+
break;
|
|
39
|
+
case 'story':
|
|
40
|
+
specific = this.getStoryFrontmatter(entity);
|
|
41
|
+
break;
|
|
42
|
+
case 'task':
|
|
43
|
+
specific = this.getTaskFrontmatter(entity);
|
|
44
|
+
break;
|
|
45
|
+
case 'decision':
|
|
46
|
+
specific = this.getDecisionFrontmatter(entity);
|
|
47
|
+
break;
|
|
48
|
+
case 'document':
|
|
49
|
+
specific = this.getDocumentFrontmatter(entity);
|
|
50
|
+
break;
|
|
51
|
+
case 'feature':
|
|
52
|
+
specific = this.getFeatureFrontmatter(entity);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
const combined = { ...base, ...specific };
|
|
56
|
+
// Remove excluded fields
|
|
57
|
+
for (const field of excludeFields) {
|
|
58
|
+
delete combined[field];
|
|
59
|
+
}
|
|
60
|
+
// Remove undefined/null values
|
|
61
|
+
return this.cleanObject(combined);
|
|
62
|
+
}
|
|
63
|
+
/** Get base frontmatter fields common to all entities */
|
|
64
|
+
getBaseFrontmatter(entity) {
|
|
65
|
+
return {
|
|
66
|
+
id: entity.id,
|
|
67
|
+
type: entity.type,
|
|
68
|
+
title: entity.title,
|
|
69
|
+
workstream: entity.workstream,
|
|
70
|
+
status: entity.status,
|
|
71
|
+
archived: entity.archived || undefined,
|
|
72
|
+
canvas_source: entity.canvas_source || undefined,
|
|
73
|
+
cssclasses: entity.cssclasses?.length ? entity.cssclasses : undefined,
|
|
74
|
+
created_at: entity.created_at,
|
|
75
|
+
updated_at: entity.updated_at,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Get milestone-specific frontmatter */
|
|
79
|
+
getMilestoneFrontmatter(entity) {
|
|
80
|
+
return {
|
|
81
|
+
target_date: entity.target_date,
|
|
82
|
+
owner: entity.owner,
|
|
83
|
+
priority: entity.priority,
|
|
84
|
+
// Hierarchy
|
|
85
|
+
children: entity.children?.length ? entity.children : undefined,
|
|
86
|
+
// Dependencies
|
|
87
|
+
depends_on: entity.depends_on?.length ? entity.depends_on : undefined,
|
|
88
|
+
blocks: entity.blocks?.length ? entity.blocks : undefined,
|
|
89
|
+
// Implementation
|
|
90
|
+
implements: entity.implements?.length ? entity.implements : undefined,
|
|
91
|
+
success_criteria: entity.success_criteria?.length ? entity.success_criteria : undefined,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** Get story-specific frontmatter */
|
|
95
|
+
getStoryFrontmatter(entity) {
|
|
96
|
+
return {
|
|
97
|
+
priority: entity.priority,
|
|
98
|
+
// Hierarchy
|
|
99
|
+
parent: entity.parent,
|
|
100
|
+
children: entity.children?.length ? entity.children : undefined,
|
|
101
|
+
// Dependencies
|
|
102
|
+
depends_on: entity.depends_on?.length ? entity.depends_on : undefined,
|
|
103
|
+
blocks: entity.blocks?.length ? entity.blocks : undefined,
|
|
104
|
+
// Implementation
|
|
105
|
+
implements: entity.implements?.length ? entity.implements : undefined,
|
|
106
|
+
acceptance_criteria: entity.acceptance_criteria?.length ? entity.acceptance_criteria : undefined,
|
|
107
|
+
tasks: entity.tasks?.length ? this.serializeInlineTasks(entity.tasks) : undefined,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/** Get task-specific frontmatter */
|
|
111
|
+
getTaskFrontmatter(entity) {
|
|
112
|
+
return {
|
|
113
|
+
// Hierarchy
|
|
114
|
+
parent: entity.parent,
|
|
115
|
+
// Dependencies
|
|
116
|
+
depends_on: entity.depends_on?.length ? entity.depends_on : undefined,
|
|
117
|
+
blocks: entity.blocks?.length ? entity.blocks : undefined,
|
|
118
|
+
// Task-specific
|
|
119
|
+
goal: entity.goal,
|
|
120
|
+
estimate_hrs: entity.estimate_hrs,
|
|
121
|
+
actual_hrs: entity.actual_hrs,
|
|
122
|
+
assignee: entity.assignee,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** Get decision-specific frontmatter */
|
|
126
|
+
getDecisionFrontmatter(entity) {
|
|
127
|
+
return {
|
|
128
|
+
decided_by: entity.decided_by,
|
|
129
|
+
decided_on: entity.decided_on,
|
|
130
|
+
// Dependencies
|
|
131
|
+
depends_on: entity.depends_on?.length ? entity.depends_on : undefined,
|
|
132
|
+
// Entities affected by this decision (renamed from blocks)
|
|
133
|
+
affects: entity.affects?.length ? entity.affects : undefined,
|
|
134
|
+
// Supersession
|
|
135
|
+
supersedes: entity.supersedes,
|
|
136
|
+
superseded_by: entity.superseded_by,
|
|
137
|
+
alternatives: entity.alternatives?.length ? entity.alternatives : undefined,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/** Get document-specific frontmatter */
|
|
141
|
+
getDocumentFrontmatter(entity) {
|
|
142
|
+
return {
|
|
143
|
+
doc_type: entity.doc_type,
|
|
144
|
+
version: entity.version,
|
|
145
|
+
owner: entity.owner,
|
|
146
|
+
// Dependencies
|
|
147
|
+
depends_on: entity.depends_on?.length ? entity.depends_on : undefined,
|
|
148
|
+
blocks: entity.blocks?.length ? entity.blocks : undefined,
|
|
149
|
+
// Implementation
|
|
150
|
+
implemented_by: entity.implemented_by?.length ? entity.implemented_by : undefined,
|
|
151
|
+
// Feature relationships
|
|
152
|
+
documents: entity.documents?.length ? entity.documents : undefined,
|
|
153
|
+
// Versioning
|
|
154
|
+
previous_version: entity.previous_version,
|
|
155
|
+
next_version: entity.next_version,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/** Get feature-specific frontmatter */
|
|
159
|
+
getFeatureFrontmatter(entity) {
|
|
160
|
+
return {
|
|
161
|
+
user_story: entity.user_story,
|
|
162
|
+
tier: entity.tier,
|
|
163
|
+
phase: entity.phase,
|
|
164
|
+
// Relationships (auto-synced)
|
|
165
|
+
implemented_by: entity.implemented_by?.length ? entity.implemented_by : undefined,
|
|
166
|
+
documented_by: entity.documented_by?.length ? entity.documented_by : undefined,
|
|
167
|
+
decided_by: entity.decided_by?.length ? entity.decided_by : undefined,
|
|
168
|
+
// Test references
|
|
169
|
+
test_refs: entity.test_refs?.length ? entity.test_refs : undefined,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// Content Extraction
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
/** Get content/body from entity */
|
|
176
|
+
getEntityContent(entity) {
|
|
177
|
+
switch (entity.type) {
|
|
178
|
+
case 'milestone':
|
|
179
|
+
return this.buildMilestoneContent(entity);
|
|
180
|
+
case 'story':
|
|
181
|
+
return this.buildStoryContent(entity);
|
|
182
|
+
case 'task':
|
|
183
|
+
return this.buildTaskContent(entity);
|
|
184
|
+
case 'decision':
|
|
185
|
+
return this.buildDecisionContent(entity);
|
|
186
|
+
case 'document':
|
|
187
|
+
return this.buildDocumentContent(entity);
|
|
188
|
+
case 'feature':
|
|
189
|
+
return this.buildFeatureContent(entity);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** Build milestone content with objective and related queries */
|
|
193
|
+
buildMilestoneContent(entity) {
|
|
194
|
+
const sections = [];
|
|
195
|
+
if (entity.objective) {
|
|
196
|
+
sections.push(entity.objective);
|
|
197
|
+
}
|
|
198
|
+
// Add Dataview queries for related items
|
|
199
|
+
sections.push(this.buildRelatedSection(entity.id, 'milestone'));
|
|
200
|
+
return sections.join('\n\n');
|
|
201
|
+
}
|
|
202
|
+
/** Build story content with outcome and notes */
|
|
203
|
+
buildStoryContent(entity) {
|
|
204
|
+
const sections = [];
|
|
205
|
+
if (entity.outcome) {
|
|
206
|
+
sections.push(`## Outcome\n\n${entity.outcome}`);
|
|
207
|
+
}
|
|
208
|
+
if (entity.notes) {
|
|
209
|
+
sections.push(`## Notes\n\n${entity.notes}`);
|
|
210
|
+
}
|
|
211
|
+
// Add Dataview queries for related items
|
|
212
|
+
sections.push(this.buildRelatedSection(entity.id, 'story'));
|
|
213
|
+
return sections.join('\n\n');
|
|
214
|
+
}
|
|
215
|
+
/** Build task content with description and notes */
|
|
216
|
+
buildTaskContent(entity) {
|
|
217
|
+
const sections = [];
|
|
218
|
+
if (entity.description) {
|
|
219
|
+
sections.push(`## Description\n\n${entity.description}`);
|
|
220
|
+
}
|
|
221
|
+
if (entity.technical_notes) {
|
|
222
|
+
sections.push(`## Technical Notes\n\n${entity.technical_notes}`);
|
|
223
|
+
}
|
|
224
|
+
if (entity.notes) {
|
|
225
|
+
sections.push(`## Notes\n\n${entity.notes}`);
|
|
226
|
+
}
|
|
227
|
+
// Add Dataview queries for related items
|
|
228
|
+
sections.push(this.buildRelatedSection(entity.id, 'task'));
|
|
229
|
+
return sections.join('\n\n');
|
|
230
|
+
}
|
|
231
|
+
/** Build decision content with context, decision, and rationale */
|
|
232
|
+
buildDecisionContent(entity) {
|
|
233
|
+
const sections = [];
|
|
234
|
+
if (entity.context) {
|
|
235
|
+
sections.push(`## Context\n\n${entity.context}`);
|
|
236
|
+
}
|
|
237
|
+
if (entity.decision) {
|
|
238
|
+
sections.push(`## Decision\n\n${entity.decision}`);
|
|
239
|
+
}
|
|
240
|
+
if (entity.rationale) {
|
|
241
|
+
sections.push(`## Rationale\n\n${entity.rationale}`);
|
|
242
|
+
}
|
|
243
|
+
// Add Dataview query for entities this decision enables
|
|
244
|
+
sections.push(this.buildDecisionRelatedSection(entity.id));
|
|
245
|
+
return sections.join('\n\n');
|
|
246
|
+
}
|
|
247
|
+
/** Build document content */
|
|
248
|
+
buildDocumentContent(entity) {
|
|
249
|
+
const sections = [];
|
|
250
|
+
if (entity.content) {
|
|
251
|
+
// Strip existing dataview blocks to prevent duplication
|
|
252
|
+
const cleanContent = this.stripDataviewBlocks(entity.content);
|
|
253
|
+
if (cleanContent) {
|
|
254
|
+
sections.push(cleanContent);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// Add Dataview query for entities implementing this document
|
|
258
|
+
sections.push(this.buildDocumentRelatedSection(entity.id));
|
|
259
|
+
return sections.join('\n\n');
|
|
260
|
+
}
|
|
261
|
+
/** Build feature content */
|
|
262
|
+
buildFeatureContent(entity) {
|
|
263
|
+
const sections = [];
|
|
264
|
+
if (entity.content) {
|
|
265
|
+
// Strip existing dataview blocks to prevent duplication
|
|
266
|
+
const cleanContent = this.stripDataviewBlocks(entity.content);
|
|
267
|
+
if (cleanContent) {
|
|
268
|
+
sections.push(cleanContent);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// Add Dataview queries for related items
|
|
272
|
+
sections.push(this.buildFeatureRelatedSection(entity.id));
|
|
273
|
+
return sections.join('\n\n');
|
|
274
|
+
}
|
|
275
|
+
/** Build related section with Dataview queries for milestone/story/task */
|
|
276
|
+
buildRelatedSection(entityId, entityType) {
|
|
277
|
+
const sections = [];
|
|
278
|
+
// Documents this entity implements (milestone, story only)
|
|
279
|
+
if (entityType === 'milestone' || entityType === 'story') {
|
|
280
|
+
sections.push(`## 📄 Documents
|
|
281
|
+
|
|
282
|
+
\`\`\`dataview
|
|
283
|
+
TABLE title as "Document", document_type as "Type", version as "Version"
|
|
284
|
+
FROM "documents"
|
|
285
|
+
WHERE contains(this.implements, id)
|
|
286
|
+
SORT title ASC
|
|
287
|
+
\`\`\``);
|
|
288
|
+
}
|
|
289
|
+
// Decisions that enable this entity
|
|
290
|
+
sections.push(`## 🎯 Decisions
|
|
291
|
+
|
|
292
|
+
\`\`\`dataview
|
|
293
|
+
TABLE title as "Decision", status as "Status", decided_at as "Date"
|
|
294
|
+
FROM "decisions"
|
|
295
|
+
WHERE contains(enables, "${entityId}")
|
|
296
|
+
SORT decided_at DESC
|
|
297
|
+
\`\`\``);
|
|
298
|
+
// For tasks: also show decisions this task depends on
|
|
299
|
+
if (entityType === 'task') {
|
|
300
|
+
sections.push(`### Blocking Decisions
|
|
301
|
+
|
|
302
|
+
\`\`\`dataview
|
|
303
|
+
TABLE title as "Decision", status as "Status"
|
|
304
|
+
FROM "decisions"
|
|
305
|
+
WHERE contains(this.depends_on, id)
|
|
306
|
+
SORT title ASC
|
|
307
|
+
\`\`\``);
|
|
308
|
+
}
|
|
309
|
+
return sections.join('\n\n');
|
|
310
|
+
}
|
|
311
|
+
/** Build related section for decisions */
|
|
312
|
+
buildDecisionRelatedSection(decisionId) {
|
|
313
|
+
return `## 🔗 Enabled Entities
|
|
314
|
+
|
|
315
|
+
\`\`\`dataview
|
|
316
|
+
TABLE title as "Entity", type as "Type", status as "Status"
|
|
317
|
+
WHERE contains(file.frontmatter.depends_on, "${decisionId}") OR contains(file.frontmatter.enabled_by, "${decisionId}")
|
|
318
|
+
SORT type ASC, title ASC
|
|
319
|
+
\`\`\`
|
|
320
|
+
|
|
321
|
+
## 📄 Affected Documents
|
|
322
|
+
|
|
323
|
+
\`\`\`dataview
|
|
324
|
+
TABLE title as "Document", version as "Version"
|
|
325
|
+
FROM "documents"
|
|
326
|
+
WHERE contains(this.affects_documents, id)
|
|
327
|
+
SORT title ASC
|
|
328
|
+
\`\`\``;
|
|
329
|
+
}
|
|
330
|
+
/** Build related section for documents */
|
|
331
|
+
buildDocumentRelatedSection(documentId) {
|
|
332
|
+
return `## 🔗 Implemented By
|
|
333
|
+
|
|
334
|
+
\`\`\`dataview
|
|
335
|
+
TABLE title as "Entity", type as "Type", status as "Status"
|
|
336
|
+
FROM ""
|
|
337
|
+
WHERE contains(implements, "${documentId}")
|
|
338
|
+
SORT type ASC, title ASC
|
|
339
|
+
\`\`\`
|
|
340
|
+
|
|
341
|
+
## 🎯 Related Decisions
|
|
342
|
+
|
|
343
|
+
\`\`\`dataview
|
|
344
|
+
TABLE title as "Decision", status as "Status", decided_at as "Date"
|
|
345
|
+
FROM "decisions"
|
|
346
|
+
WHERE contains(affects_documents, "${documentId}")
|
|
347
|
+
SORT decided_at DESC
|
|
348
|
+
\`\`\``;
|
|
349
|
+
}
|
|
350
|
+
/** Build related section for features */
|
|
351
|
+
buildFeatureRelatedSection(featureId) {
|
|
352
|
+
return `## 🔗 Implemented By
|
|
353
|
+
|
|
354
|
+
\`\`\`dataview
|
|
355
|
+
TABLE title as "Entity", type as "Type", status as "Status"
|
|
356
|
+
FROM ""
|
|
357
|
+
WHERE contains(implements, "${featureId}")
|
|
358
|
+
SORT type ASC, title ASC
|
|
359
|
+
\`\`\`
|
|
360
|
+
|
|
361
|
+
## 📄 Documentation
|
|
362
|
+
|
|
363
|
+
\`\`\`dataview
|
|
364
|
+
TABLE title as "Document", doc_type as "Type", status as "Status"
|
|
365
|
+
FROM "documents"
|
|
366
|
+
WHERE contains(documents, "${featureId}")
|
|
367
|
+
SORT title ASC
|
|
368
|
+
\`\`\`
|
|
369
|
+
|
|
370
|
+
## 🎯 Related Decisions
|
|
371
|
+
|
|
372
|
+
\`\`\`dataview
|
|
373
|
+
TABLE title as "Decision", status as "Status", decided_on as "Date"
|
|
374
|
+
FROM "decisions"
|
|
375
|
+
WHERE contains(affects, "${featureId}")
|
|
376
|
+
SORT decided_on DESC
|
|
377
|
+
\`\`\``;
|
|
378
|
+
}
|
|
379
|
+
// ---------------------------------------------------------------------------
|
|
380
|
+
// YAML Serialization
|
|
381
|
+
// ---------------------------------------------------------------------------
|
|
382
|
+
/** Convert object to YAML string */
|
|
383
|
+
toYaml(obj) {
|
|
384
|
+
const lines = [];
|
|
385
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
386
|
+
if (value === undefined || value === null)
|
|
387
|
+
continue;
|
|
388
|
+
const yamlValue = this.valueToYaml(value, 0);
|
|
389
|
+
lines.push(`${key}: ${yamlValue}`);
|
|
390
|
+
}
|
|
391
|
+
return lines.join('\n') + '\n';
|
|
392
|
+
}
|
|
393
|
+
/** Convert a value to YAML representation */
|
|
394
|
+
valueToYaml(value, indent) {
|
|
395
|
+
if (value === null || value === undefined) {
|
|
396
|
+
return 'null';
|
|
397
|
+
}
|
|
398
|
+
if (typeof value === 'string') {
|
|
399
|
+
// Check if string needs quoting
|
|
400
|
+
if (this.needsQuoting(value)) {
|
|
401
|
+
return `"${this.escapeString(value)}"`;
|
|
402
|
+
}
|
|
403
|
+
return value;
|
|
404
|
+
}
|
|
405
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
406
|
+
return String(value);
|
|
407
|
+
}
|
|
408
|
+
if (Array.isArray(value)) {
|
|
409
|
+
if (value.length === 0)
|
|
410
|
+
return '[]';
|
|
411
|
+
// Check if array contains objects
|
|
412
|
+
if (typeof value[0] === 'object' && value[0] !== null) {
|
|
413
|
+
return this.arrayOfObjectsToYaml(value, indent);
|
|
414
|
+
}
|
|
415
|
+
// Simple array - inline format
|
|
416
|
+
const items = value.map(v => this.valueToYaml(v, indent));
|
|
417
|
+
return `[${items.join(', ')}]`;
|
|
418
|
+
}
|
|
419
|
+
if (typeof value === 'object') {
|
|
420
|
+
return this.objectToYaml(value, indent + 2);
|
|
421
|
+
}
|
|
422
|
+
return String(value);
|
|
423
|
+
}
|
|
424
|
+
/** Convert array of objects to YAML */
|
|
425
|
+
arrayOfObjectsToYaml(arr, indent) {
|
|
426
|
+
const lines = [''];
|
|
427
|
+
const pad = ' '.repeat(indent + 2);
|
|
428
|
+
for (const item of arr) {
|
|
429
|
+
const entries = Object.entries(item);
|
|
430
|
+
if (entries.length === 0)
|
|
431
|
+
continue;
|
|
432
|
+
const [firstKey, firstValue] = entries[0];
|
|
433
|
+
lines.push(`${pad}- ${firstKey}: ${this.valueToYaml(firstValue, indent + 4)}`);
|
|
434
|
+
for (let i = 1; i < entries.length; i++) {
|
|
435
|
+
const [key, val] = entries[i];
|
|
436
|
+
lines.push(`${pad} ${key}: ${this.valueToYaml(val, indent + 4)}`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return lines.join('\n');
|
|
440
|
+
}
|
|
441
|
+
/** Convert object to YAML */
|
|
442
|
+
objectToYaml(obj, indent) {
|
|
443
|
+
const lines = [''];
|
|
444
|
+
const pad = ' '.repeat(indent);
|
|
445
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
446
|
+
if (value === undefined || value === null)
|
|
447
|
+
continue;
|
|
448
|
+
lines.push(`${pad}${key}: ${this.valueToYaml(value, indent)}`);
|
|
449
|
+
}
|
|
450
|
+
return lines.join('\n');
|
|
451
|
+
}
|
|
452
|
+
/** Check if string needs quoting */
|
|
453
|
+
needsQuoting(str) {
|
|
454
|
+
// Quote if contains special characters or looks like other types
|
|
455
|
+
if (/^[\d.]+$/.test(str))
|
|
456
|
+
return true; // Looks like number
|
|
457
|
+
if (/^(true|false|null|yes|no|on|off)$/i.test(str))
|
|
458
|
+
return true;
|
|
459
|
+
if (/[:#\[\]{}|>&*!?,]/.test(str))
|
|
460
|
+
return true;
|
|
461
|
+
if (str.includes('\n'))
|
|
462
|
+
return true;
|
|
463
|
+
if (str.startsWith(' ') || str.endsWith(' '))
|
|
464
|
+
return true;
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
/** Escape string for YAML */
|
|
468
|
+
escapeString(str) {
|
|
469
|
+
return str
|
|
470
|
+
.replace(/\\/g, '\\\\')
|
|
471
|
+
.replace(/"/g, '\\"')
|
|
472
|
+
.replace(/\n/g, '\\n')
|
|
473
|
+
.replace(/\t/g, '\\t');
|
|
474
|
+
}
|
|
475
|
+
// ---------------------------------------------------------------------------
|
|
476
|
+
// Helper Methods
|
|
477
|
+
// ---------------------------------------------------------------------------
|
|
478
|
+
/** Serialize inline tasks for frontmatter */
|
|
479
|
+
serializeInlineTasks(tasks) {
|
|
480
|
+
return tasks.map(task => ({
|
|
481
|
+
number: task.number,
|
|
482
|
+
name: task.name,
|
|
483
|
+
goal: task.goal,
|
|
484
|
+
status: task.status,
|
|
485
|
+
estimate_hrs: task.estimate_hrs,
|
|
486
|
+
description: task.description,
|
|
487
|
+
}));
|
|
488
|
+
}
|
|
489
|
+
/** Remove undefined/null values from object */
|
|
490
|
+
cleanObject(obj) {
|
|
491
|
+
const cleaned = {};
|
|
492
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
493
|
+
if (value !== undefined && value !== null) {
|
|
494
|
+
cleaned[key] = value;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return cleaned;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Strip dataview blocks and their section headers from content.
|
|
501
|
+
* This prevents duplication when re-serializing entities.
|
|
502
|
+
*
|
|
503
|
+
* Removes:
|
|
504
|
+
* - Dataview code blocks (```dataview ... ```)
|
|
505
|
+
* - Section headers that precede dataview blocks (## 🔗 Implemented By, etc.)
|
|
506
|
+
*/
|
|
507
|
+
stripDataviewBlocks(content) {
|
|
508
|
+
// Pattern to match section headers followed by dataview blocks
|
|
509
|
+
// Matches: ## Header\n\n```dataview...```
|
|
510
|
+
const sectionWithDataviewPattern = /^##\s+[^\n]+\n+```dataview[\s\S]*?```\n*/gm;
|
|
511
|
+
// Pattern to match standalone dataview blocks
|
|
512
|
+
const standaloneDataviewPattern = /```dataview[\s\S]*?```\n*/g;
|
|
513
|
+
let cleaned = content;
|
|
514
|
+
// First remove section headers with their dataview blocks
|
|
515
|
+
cleaned = cleaned.replace(sectionWithDataviewPattern, '');
|
|
516
|
+
// Then remove any remaining standalone dataview blocks
|
|
517
|
+
cleaned = cleaned.replace(standaloneDataviewPattern, '');
|
|
518
|
+
// Clean up excessive newlines
|
|
519
|
+
cleaned = cleaned.replace(/\n{3,}/g, '\n\n');
|
|
520
|
+
return cleaned.trim();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
// =============================================================================
|
|
524
|
+
// CSS Classes Generator
|
|
525
|
+
// =============================================================================
|
|
526
|
+
/**
|
|
527
|
+
* Generate CSS classes for visual differentiation on canvas.
|
|
528
|
+
*
|
|
529
|
+
* CSS classes control:
|
|
530
|
+
* - Border thickness: entity type (milestone=4px, story=2px, task=1px)
|
|
531
|
+
* - Border color: workstream type
|
|
532
|
+
* - Visual state: status indicators
|
|
533
|
+
*/
|
|
534
|
+
export function generateCssClasses(entity) {
|
|
535
|
+
const classes = [];
|
|
536
|
+
// Type class - controls border thickness and node size
|
|
537
|
+
classes.push(`canvas-${entity.type}`);
|
|
538
|
+
// Workstream class - controls border color
|
|
539
|
+
const workstream = getWorkstreamFromEntity(entity);
|
|
540
|
+
if (workstream) {
|
|
541
|
+
classes.push(`canvas-workstream-${normalizeForCss(workstream)}`);
|
|
542
|
+
}
|
|
543
|
+
// Status class - controls visual state (opacity, badges, etc.)
|
|
544
|
+
if (entity.status) {
|
|
545
|
+
classes.push(`canvas-status-${normalizeForCss(entity.status)}`);
|
|
546
|
+
}
|
|
547
|
+
// Priority class (optional, for milestones and stories)
|
|
548
|
+
const priority = getPriorityFromEntity(entity);
|
|
549
|
+
if (priority) {
|
|
550
|
+
classes.push(`canvas-priority-${normalizeForCss(priority)}`);
|
|
551
|
+
}
|
|
552
|
+
return classes;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Get workstream from entity for CSS class generation.
|
|
556
|
+
*/
|
|
557
|
+
function getWorkstreamFromEntity(entity) {
|
|
558
|
+
return entity.workstream || null;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Get priority from entity if applicable.
|
|
562
|
+
*/
|
|
563
|
+
function getPriorityFromEntity(entity) {
|
|
564
|
+
switch (entity.type) {
|
|
565
|
+
case 'milestone':
|
|
566
|
+
return entity.priority;
|
|
567
|
+
case 'story':
|
|
568
|
+
return entity.priority;
|
|
569
|
+
default:
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Normalize a string for use in CSS class names.
|
|
575
|
+
* Converts to lowercase and replaces spaces with hyphens.
|
|
576
|
+
*/
|
|
577
|
+
function normalizeForCss(value) {
|
|
578
|
+
return value
|
|
579
|
+
.toLowerCase()
|
|
580
|
+
.replace(/\s+/g, '-')
|
|
581
|
+
.replace(/[^a-z0-9-]/g, '');
|
|
582
|
+
}
|
|
583
|
+
//# sourceMappingURL=entity-serializer.js.map
|