busy-cli 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +129 -0
  2. package/dist/builders/context.d.ts +50 -0
  3. package/dist/builders/context.d.ts.map +1 -0
  4. package/dist/builders/context.js +190 -0
  5. package/dist/cache/index.d.ts +100 -0
  6. package/dist/cache/index.d.ts.map +1 -0
  7. package/dist/cache/index.js +270 -0
  8. package/dist/cli/index.d.ts +3 -0
  9. package/dist/cli/index.d.ts.map +1 -0
  10. package/dist/cli/index.js +463 -0
  11. package/dist/commands/package.d.ts +96 -0
  12. package/dist/commands/package.d.ts.map +1 -0
  13. package/dist/commands/package.js +285 -0
  14. package/dist/index.d.ts +7 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +7 -0
  17. package/dist/loader.d.ts +6 -0
  18. package/dist/loader.d.ts.map +1 -0
  19. package/dist/loader.js +361 -0
  20. package/dist/merge.d.ts +16 -0
  21. package/dist/merge.d.ts.map +1 -0
  22. package/dist/merge.js +102 -0
  23. package/dist/package/manifest.d.ts +59 -0
  24. package/dist/package/manifest.d.ts.map +1 -0
  25. package/dist/package/manifest.js +265 -0
  26. package/dist/parser.d.ts +28 -0
  27. package/dist/parser.d.ts.map +1 -0
  28. package/dist/parser.js +220 -0
  29. package/dist/parsers/frontmatter.d.ts +14 -0
  30. package/dist/parsers/frontmatter.d.ts.map +1 -0
  31. package/dist/parsers/frontmatter.js +110 -0
  32. package/dist/parsers/imports.d.ts +48 -0
  33. package/dist/parsers/imports.d.ts.map +1 -0
  34. package/dist/parsers/imports.js +147 -0
  35. package/dist/parsers/links.d.ts +12 -0
  36. package/dist/parsers/links.d.ts.map +1 -0
  37. package/dist/parsers/links.js +79 -0
  38. package/dist/parsers/localdefs.d.ts +6 -0
  39. package/dist/parsers/localdefs.d.ts.map +1 -0
  40. package/dist/parsers/localdefs.js +132 -0
  41. package/dist/parsers/operations.d.ts +32 -0
  42. package/dist/parsers/operations.d.ts.map +1 -0
  43. package/dist/parsers/operations.js +313 -0
  44. package/dist/parsers/sections.d.ts +15 -0
  45. package/dist/parsers/sections.d.ts.map +1 -0
  46. package/dist/parsers/sections.js +173 -0
  47. package/dist/parsers/tools.d.ts +30 -0
  48. package/dist/parsers/tools.d.ts.map +1 -0
  49. package/dist/parsers/tools.js +178 -0
  50. package/dist/parsers/triggers.d.ts +35 -0
  51. package/dist/parsers/triggers.d.ts.map +1 -0
  52. package/dist/parsers/triggers.js +219 -0
  53. package/dist/providers/base.d.ts +60 -0
  54. package/dist/providers/base.d.ts.map +1 -0
  55. package/dist/providers/base.js +34 -0
  56. package/dist/providers/github.d.ts +18 -0
  57. package/dist/providers/github.d.ts.map +1 -0
  58. package/dist/providers/github.js +109 -0
  59. package/dist/providers/gitlab.d.ts +18 -0
  60. package/dist/providers/gitlab.d.ts.map +1 -0
  61. package/dist/providers/gitlab.js +101 -0
  62. package/dist/providers/index.d.ts +13 -0
  63. package/dist/providers/index.d.ts.map +1 -0
  64. package/dist/providers/index.js +17 -0
  65. package/dist/providers/local.d.ts +31 -0
  66. package/dist/providers/local.d.ts.map +1 -0
  67. package/dist/providers/local.js +116 -0
  68. package/dist/providers/url.d.ts +16 -0
  69. package/dist/providers/url.d.ts.map +1 -0
  70. package/dist/providers/url.js +45 -0
  71. package/dist/registry/index.d.ts +99 -0
  72. package/dist/registry/index.d.ts.map +1 -0
  73. package/dist/registry/index.js +320 -0
  74. package/dist/types/schema.d.ts +3259 -0
  75. package/dist/types/schema.d.ts.map +1 -0
  76. package/dist/types/schema.js +258 -0
  77. package/dist/utils/logger.d.ts +19 -0
  78. package/dist/utils/logger.d.ts.map +1 -0
  79. package/dist/utils/logger.js +23 -0
  80. package/dist/utils/slugify.d.ts +14 -0
  81. package/dist/utils/slugify.d.ts.map +1 -0
  82. package/dist/utils/slugify.js +28 -0
  83. package/package.json +61 -0
  84. package/src/__tests__/cache.test.ts +393 -0
  85. package/src/__tests__/cli-package.test.ts +667 -0
  86. package/src/__tests__/fixtures/automated-workflow.busy.md +84 -0
  87. package/src/__tests__/fixtures/concept.busy.md +30 -0
  88. package/src/__tests__/fixtures/document.busy.md +44 -0
  89. package/src/__tests__/fixtures/simple-operation.busy.md +45 -0
  90. package/src/__tests__/fixtures/tool-document.busy.md +71 -0
  91. package/src/__tests__/fixtures/tool.busy.md +54 -0
  92. package/src/__tests__/imports.test.ts +244 -0
  93. package/src/__tests__/integration.test.ts +432 -0
  94. package/src/__tests__/operations.test.ts +408 -0
  95. package/src/__tests__/package-manifest.test.ts +455 -0
  96. package/src/__tests__/providers.test.ts +672 -0
  97. package/src/__tests__/registry.test.ts +402 -0
  98. package/src/__tests__/schema.test.ts +467 -0
  99. package/src/__tests__/tools.test.ts +376 -0
  100. package/src/__tests__/triggers.test.ts +312 -0
  101. package/src/builders/context.ts +294 -0
  102. package/src/cache/index.ts +312 -0
  103. package/src/cli/index.ts +514 -0
  104. package/src/commands/package.ts +392 -0
  105. package/src/index.ts +46 -0
  106. package/src/loader.ts +474 -0
  107. package/src/merge.ts +126 -0
  108. package/src/package/manifest.ts +349 -0
  109. package/src/parser.ts +278 -0
  110. package/src/parsers/frontmatter.ts +135 -0
  111. package/src/parsers/imports.ts +196 -0
  112. package/src/parsers/links.ts +108 -0
  113. package/src/parsers/localdefs.ts +166 -0
  114. package/src/parsers/operations.ts +404 -0
  115. package/src/parsers/sections.ts +230 -0
  116. package/src/parsers/tools.ts +215 -0
  117. package/src/parsers/triggers.ts +252 -0
  118. package/src/providers/base.ts +77 -0
  119. package/src/providers/github.ts +129 -0
  120. package/src/providers/gitlab.ts +121 -0
  121. package/src/providers/index.ts +25 -0
  122. package/src/providers/local.ts +129 -0
  123. package/src/providers/url.ts +56 -0
  124. package/src/registry/index.ts +408 -0
  125. package/src/types/schema.ts +369 -0
  126. package/src/utils/logger.ts +25 -0
  127. package/src/utils/slugify.ts +31 -0
  128. package/tsconfig.json +21 -0
@@ -0,0 +1,14 @@
1
+ import { FrontMatter, ConceptBase } from '../types/schema.js';
2
+ export interface ParsedFrontMatter {
3
+ frontmatter: FrontMatter;
4
+ content: string;
5
+ docId: string;
6
+ kind: ConceptBase['kind'];
7
+ types: string[];
8
+ extends: string[];
9
+ }
10
+ /**
11
+ * Parse front-matter from markdown content
12
+ */
13
+ export declare function parseFrontMatter(fileContent: string, filePath: string): ParsedFrontMatter;
14
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/parsers/frontmatter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAqB,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjF,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,iBAAiB,CAiFnB"}
@@ -0,0 +1,110 @@
1
+ import matter from 'gray-matter';
2
+ import { FrontMatterSchema } from '../types/schema.js';
3
+ import { normalizeDocId, getBasename } from '../utils/slugify.js';
4
+ import { debug, warn } from '../utils/logger.js';
5
+ /**
6
+ * Parse front-matter from markdown content
7
+ */
8
+ export function parseFrontMatter(fileContent, filePath) {
9
+ let data;
10
+ let content;
11
+ // Extract only the first frontmatter block to avoid "multiple documents" error
12
+ // when the body contains --- horizontal rules
13
+ const frontmatterMatch = fileContent.match(/^---\n([\s\S]*?)\n---/);
14
+ if (frontmatterMatch) {
15
+ try {
16
+ const parsed = matter(frontmatterMatch[0]);
17
+ data = parsed.data;
18
+ content = fileContent.slice(frontmatterMatch[0].length);
19
+ }
20
+ catch (err) {
21
+ warn(`Failed to parse YAML frontmatter in ${filePath}: ${err}`, { file: filePath });
22
+ data = {};
23
+ content = fileContent;
24
+ }
25
+ }
26
+ else {
27
+ // No frontmatter found
28
+ data = {};
29
+ content = fileContent;
30
+ }
31
+ debug.frontmatter('Parsing frontmatter for %s', filePath);
32
+ // Validate frontmatter
33
+ let frontmatter;
34
+ try {
35
+ frontmatter = FrontMatterSchema.parse(data);
36
+ }
37
+ catch (err) {
38
+ warn(`Invalid frontmatter schema in ${filePath}`, { file: filePath });
39
+ // Provide defaults if validation fails
40
+ frontmatter = {
41
+ Name: getBasename(filePath),
42
+ Type: [],
43
+ Description: undefined,
44
+ Tags: [],
45
+ Extends: [],
46
+ };
47
+ }
48
+ // Normalize docId from Name or filename
49
+ const docId = frontmatter.Name
50
+ ? normalizeDocId(frontmatter.Name)
51
+ : normalizeDocId(getBasename(filePath));
52
+ // Normalize types - strip markdown link brackets like [Document] -> Document
53
+ const types = (frontmatter.Type ?? []).map(stripMarkdownBrackets);
54
+ // Infer kind from types
55
+ const kind = inferKind(types);
56
+ // Normalize extends - also strip brackets
57
+ const extendsFromFm = (frontmatter.Extends ?? []).map(stripMarkdownBrackets);
58
+ const extendsFromTypes = inferExtendsFromTypes(types);
59
+ const extends_ = Array.from(new Set([...extendsFromFm, ...extendsFromTypes]));
60
+ // Normalize tags
61
+ const tags = (frontmatter.Tags ?? []).map(stripMarkdownBrackets);
62
+ debug.frontmatter('Parsed: docId=%s, kind=%s, types=%o, extends=%o', docId, kind, types, extends_);
63
+ return {
64
+ frontmatter: {
65
+ ...frontmatter,
66
+ Type: types,
67
+ Extends: extends_,
68
+ Tags: tags,
69
+ },
70
+ content,
71
+ docId,
72
+ kind,
73
+ types,
74
+ extends: extends_,
75
+ };
76
+ }
77
+ /**
78
+ * Strip markdown link brackets from a string
79
+ * [Document] -> Document
80
+ * [[Document]] -> Document
81
+ */
82
+ function stripMarkdownBrackets(str) {
83
+ return str.replace(/^\[+|\]+$/g, '');
84
+ }
85
+ /**
86
+ * Infer kind from types array
87
+ */
88
+ function inferKind(types) {
89
+ const typesLower = types.map((t) => t.toLowerCase());
90
+ if (typesLower.includes('document'))
91
+ return 'document';
92
+ if (typesLower.includes('operation'))
93
+ return 'operation';
94
+ if (typesLower.includes('checklist'))
95
+ return 'checklist';
96
+ if (typesLower.includes('tool'))
97
+ return 'tool';
98
+ if (typesLower.includes('playbook'))
99
+ return 'playbook';
100
+ return 'concept';
101
+ }
102
+ /**
103
+ * Infer extends from types
104
+ * All Type references should be included in extends
105
+ */
106
+ function inferExtendsFromTypes(types) {
107
+ // All types are also extends - they define what this concept is based on
108
+ return types;
109
+ }
110
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1,48 @@
1
+ import { ImportDef, DocId, Import } from '../types/schema.js';
2
+ /**
3
+ * Parse reference-style imports from markdown content
4
+ * Matches busy-python format: [ConceptName]: path/to/file.md[#anchor]
5
+ *
6
+ * @returns Object with imports array and symbols table
7
+ */
8
+ export declare function parseImports(content: string): {
9
+ imports: Import[];
10
+ symbols: Record<string, {
11
+ docId?: string;
12
+ slug?: string;
13
+ }>;
14
+ };
15
+ /**
16
+ * Resolve an import path to docId and optional slug
17
+ * Used for import resolution against a file map
18
+ */
19
+ export declare function resolveImportTarget(target: string, fileMap: Map<string, {
20
+ docId: string;
21
+ path: string;
22
+ }>): {
23
+ docId?: string;
24
+ slug?: string;
25
+ };
26
+ /**
27
+ * Extract reference-style imports from markdown content (LEGACY)
28
+ * Returns ImportDef objects for graph-based representation
29
+ */
30
+ export declare function extractImports(content: string, docId: DocId): {
31
+ imports: ImportDef[];
32
+ symbols: Record<string, {
33
+ docId?: string;
34
+ slug?: string;
35
+ }>;
36
+ };
37
+ /**
38
+ * Resolve an import target to {docId, slug} (LEGACY)
39
+ * This version requires currentDocId parameter for backward compatibility
40
+ */
41
+ export declare function legacyResolveImportTarget(target: string, currentDocId: DocId, fileMap: Map<string, {
42
+ docId: string;
43
+ path: string;
44
+ }>): {
45
+ docId?: string;
46
+ slug?: string;
47
+ };
48
+ //# sourceMappingURL=imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/parsers/imports.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAO9D;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,GACd;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CA2BnF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAuCnC;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GACX;IAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CA4CtF;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,KAAK,EACnB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAiCnC"}
@@ -0,0 +1,147 @@
1
+ import { unified } from 'unified';
2
+ import remarkParse from 'remark-parse';
3
+ import remarkFrontmatter from 'remark-frontmatter';
4
+ import { visit } from 'unist-util-visit';
5
+ import { debug } from '../utils/logger.js';
6
+ // =============================================================================
7
+ // NEW PARSER FUNCTIONS - busy-python compatible
8
+ // =============================================================================
9
+ /**
10
+ * Parse reference-style imports from markdown content
11
+ * Matches busy-python format: [ConceptName]: path/to/file.md[#anchor]
12
+ *
13
+ * @returns Object with imports array and symbols table
14
+ */
15
+ export function parseImports(content) {
16
+ const imports = [];
17
+ const symbols = {};
18
+ // Regex pattern matching busy-python: r"\[([^\]]+)\]:\s*([^\s#]+)(?:#([^\s]+))?"
19
+ const importPattern = /^\[([^\]]+)\]:\s*([^\s#]+)(?:#([^\s]+))?$/gm;
20
+ let match;
21
+ while ((match = importPattern.exec(content)) !== null) {
22
+ const [, conceptName, path, anchor] = match;
23
+ const importDef = {
24
+ conceptName,
25
+ path,
26
+ anchor: anchor || undefined,
27
+ };
28
+ imports.push(importDef);
29
+ // Add to symbol table for later resolution
30
+ symbols[conceptName] = {
31
+ docId: undefined,
32
+ slug: anchor || undefined,
33
+ };
34
+ }
35
+ return { imports, symbols };
36
+ }
37
+ /**
38
+ * Resolve an import path to docId and optional slug
39
+ * Used for import resolution against a file map
40
+ */
41
+ export function resolveImportTarget(target, fileMap) {
42
+ // Parse target: "file.md", "./file.md", "../core/file.md", or "file.md#slug"
43
+ const hashIndex = target.indexOf('#');
44
+ let filePath = target;
45
+ let slug;
46
+ if (hashIndex !== -1) {
47
+ filePath = target.slice(0, hashIndex);
48
+ slug = target.slice(hashIndex + 1);
49
+ }
50
+ // Remove leading ./ if present
51
+ filePath = filePath.replace(/^\.\//, '');
52
+ // Try multiple resolution strategies:
53
+ // 1. Full path as provided
54
+ let fileInfo = fileMap.get(filePath);
55
+ // 2. Try just the basename
56
+ if (!fileInfo) {
57
+ const basename = filePath.split('/').pop() || filePath;
58
+ fileInfo = fileMap.get(basename);
59
+ }
60
+ // 3. Try without extension
61
+ if (!fileInfo) {
62
+ const basename = filePath.split('/').pop() || filePath;
63
+ const withoutExt = basename.replace(/\.busy\.md$/, '').replace(/\.md$/, '');
64
+ fileInfo = fileMap.get(withoutExt);
65
+ }
66
+ if (!fileInfo) {
67
+ return slug ? { slug } : {};
68
+ }
69
+ return {
70
+ docId: fileInfo.docId,
71
+ slug,
72
+ };
73
+ }
74
+ // =============================================================================
75
+ // LEGACY FUNCTIONS - kept for backward compatibility
76
+ // =============================================================================
77
+ /**
78
+ * Extract reference-style imports from markdown content (LEGACY)
79
+ * Returns ImportDef objects for graph-based representation
80
+ */
81
+ export function extractImports(content, docId) {
82
+ debug.imports('Extracting imports for %s', docId);
83
+ const processor = unified().use(remarkParse).use(remarkFrontmatter, ['yaml']);
84
+ const tree = processor.parse(content);
85
+ const imports = [];
86
+ const symbols = {};
87
+ // Visit definition nodes (reference-style links)
88
+ visit(tree, 'definition', (node) => {
89
+ const label = node.label ?? node.identifier;
90
+ const target = node.url;
91
+ debug.imports('Found import: [%s]: %s', label, target);
92
+ const importDef = {
93
+ kind: 'importdef',
94
+ id: `${docId}::import::${label}`,
95
+ docId,
96
+ slug: label.toLowerCase(),
97
+ name: label,
98
+ content: '', // Imports don't have content
99
+ types: [],
100
+ extends: [],
101
+ sectionRef: '', // Imports don't belong to a section
102
+ label,
103
+ target,
104
+ resolved: undefined, // Will be resolved later
105
+ };
106
+ imports.push(importDef);
107
+ // Add to symbol table (will be fully resolved later)
108
+ symbols[label] = {
109
+ docId: undefined,
110
+ slug: undefined,
111
+ };
112
+ });
113
+ debug.imports('Found %d imports', imports.length);
114
+ return { imports, symbols };
115
+ }
116
+ /**
117
+ * Resolve an import target to {docId, slug} (LEGACY)
118
+ * This version requires currentDocId parameter for backward compatibility
119
+ */
120
+ export function legacyResolveImportTarget(target, currentDocId, fileMap) {
121
+ // Parse target: "./file.md", "../core/file.md", or "./file.md#slug"
122
+ const match = target.match(/^\.{1,2}\/(.+?)(#(.+))?$/);
123
+ if (!match) {
124
+ debug.imports('Invalid import target: %s', target);
125
+ return {};
126
+ }
127
+ const [, filePath, , slug] = match;
128
+ // Try multiple resolution strategies:
129
+ // 1. Full relative path
130
+ // 2. Just the basename
131
+ // 3. Basename with different extensions
132
+ let fileInfo = fileMap.get(filePath);
133
+ if (!fileInfo) {
134
+ // Try just the basename
135
+ const basename = filePath.split('/').pop() || filePath;
136
+ fileInfo = fileMap.get(basename);
137
+ }
138
+ if (!fileInfo) {
139
+ debug.imports('File not found in map: %s', filePath);
140
+ return { slug };
141
+ }
142
+ return {
143
+ docId: fileInfo.docId,
144
+ slug,
145
+ };
146
+ }
147
+ //# sourceMappingURL=imports.js.map
@@ -0,0 +1,12 @@
1
+ import { Section, Edge } from '../types/schema.js';
2
+ /**
3
+ * Extract links from a section and create edges
4
+ */
5
+ export declare function extractLinksFromSection(section: Section, content: string, symbols: Record<string, {
6
+ docId?: string;
7
+ slug?: string;
8
+ }>, fileMap: Map<string, {
9
+ docId: string;
10
+ path: string;
11
+ }>): Edge[];
12
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/parsers/links.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAY,MAAM,oBAAoB,CAAC;AAI7D;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD,IAAI,EAAE,CAsDR"}
@@ -0,0 +1,79 @@
1
+ import { unified } from 'unified';
2
+ import remarkParse from 'remark-parse';
3
+ import remarkFrontmatter from 'remark-frontmatter';
4
+ import { visit } from 'unist-util-visit';
5
+ import { debug } from '../utils/logger.js';
6
+ /**
7
+ * Extract links from a section and create edges
8
+ */
9
+ export function extractLinksFromSection(section, content, symbols, fileMap) {
10
+ debug.links('Extracting links from section %s', section.id);
11
+ const processor = unified().use(remarkParse).use(remarkFrontmatter, ['yaml']);
12
+ const tree = processor.parse(content);
13
+ const edges = [];
14
+ // Visit link nodes
15
+ visit(tree, 'link', (node) => {
16
+ const href = node.url;
17
+ const resolved = resolveLink(href, section.docId, fileMap);
18
+ if (resolved) {
19
+ // Temporarily mark as 'ref', will be reclassified in loader
20
+ edges.push({
21
+ from: section.id,
22
+ to: resolved,
23
+ role: 'ref',
24
+ });
25
+ }
26
+ });
27
+ // Visit link reference nodes
28
+ visit(tree, 'linkReference', (node) => {
29
+ const label = node.label ?? node.identifier;
30
+ // Resolve via symbol table
31
+ const symbol = symbols[label];
32
+ if (symbol) {
33
+ let resolved;
34
+ if (symbol.docId && symbol.slug) {
35
+ resolved = `${symbol.docId}#${symbol.slug}`;
36
+ }
37
+ else if (symbol.docId) {
38
+ resolved = symbol.docId;
39
+ }
40
+ if (resolved) {
41
+ // Temporarily mark as 'ref', will be reclassified in loader
42
+ edges.push({
43
+ from: section.id,
44
+ to: resolved,
45
+ role: 'ref',
46
+ });
47
+ }
48
+ }
49
+ });
50
+ debug.links('Found %d edges from section', edges.length);
51
+ return edges;
52
+ }
53
+ /**
54
+ * Resolve a link href to a node ID
55
+ */
56
+ function resolveLink(href, currentDocId, fileMap) {
57
+ // Handle internal anchors: #slug
58
+ if (href.startsWith('#')) {
59
+ const slug = href.slice(1);
60
+ return `${currentDocId}#${slug}`;
61
+ }
62
+ // Handle relative file links: ./file.md or ./file.md#slug
63
+ const match = href.match(/^\.\/(.+?)(#(.+))?$/);
64
+ if (match) {
65
+ const [, filePath, , slug] = match;
66
+ const fileInfo = fileMap.get(filePath);
67
+ if (!fileInfo) {
68
+ debug.links('File not found: %s', filePath);
69
+ return undefined;
70
+ }
71
+ if (slug) {
72
+ return `${fileInfo.docId}#${slug}`;
73
+ }
74
+ return fileInfo.docId;
75
+ }
76
+ // External link - return as-is or skip
77
+ return href.startsWith('http') ? href : undefined;
78
+ }
79
+ //# sourceMappingURL=links.js.map
@@ -0,0 +1,6 @@
1
+ import { Section, LocalDef, DocId } from '../types/schema.js';
2
+ /**
3
+ * Extract Local Definitions from sections
4
+ */
5
+ export declare function extractLocalDefs(sections: Section[], docId: DocId, filePath: string): LocalDef[];
6
+ //# sourceMappingURL=localdefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localdefs.d.ts","sourceRoot":"","sources":["../../src/parsers/localdefs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAY9D;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,GACf,QAAQ,EAAE,CA2BZ"}
@@ -0,0 +1,132 @@
1
+ import { findSection, getAllSections, getSectionExtends } from './sections.js';
2
+ import { debug } from '../utils/logger.js';
3
+ const LOCAL_DEFS_ALIASES = [
4
+ 'local definitions',
5
+ 'definitions',
6
+ 'glossary',
7
+ 'local-definitions-section',
8
+ ];
9
+ /**
10
+ * Extract Local Definitions from sections
11
+ */
12
+ export function extractLocalDefs(sections, docId, filePath) {
13
+ debug.localdefs('Extracting local definitions for %s', docId);
14
+ // Find the Local Definitions section
15
+ const localDefsSection = findLocalDefinitionsSection(sections);
16
+ if (!localDefsSection) {
17
+ debug.localdefs('No Local Definitions section found');
18
+ return [];
19
+ }
20
+ debug.localdefs('Found Local Definitions section: %s', localDefsSection.title);
21
+ // Extract all subheadings as LocalDefs
22
+ const localdefs = [];
23
+ for (const child of getAllSections(localDefsSection.children)) {
24
+ const localdef = createLocalDef(child, docId, filePath);
25
+ localdefs.push(localdef);
26
+ }
27
+ debug.localdefs('Extracted %d local definitions', localdefs.length);
28
+ return localdefs;
29
+ }
30
+ /**
31
+ * Find the Local Definitions section (case-insensitive)
32
+ */
33
+ function findLocalDefinitionsSection(sections) {
34
+ for (const alias of LOCAL_DEFS_ALIASES) {
35
+ const section = findSection(sections, alias);
36
+ if (section) {
37
+ return section;
38
+ }
39
+ }
40
+ return undefined;
41
+ }
42
+ /**
43
+ * Create a LocalDef from a section
44
+ */
45
+ function createLocalDef(section, docId, filePath) {
46
+ const slug = section.slug;
47
+ const id = `${docId}::${slug}`;
48
+ // Parse extends from content
49
+ const { extends: extendsFromContent } = parseLocalDefAttrs(section.content);
50
+ // Get extends from section heading (e.g., ## [MyDef][Type])
51
+ const extendsFromHeading = getSectionExtends(section.id);
52
+ // Combine both sources of extends
53
+ const extends_ = Array.from(new Set([...extendsFromContent, ...extendsFromHeading]));
54
+ return {
55
+ kind: 'localdef',
56
+ id,
57
+ docId,
58
+ slug,
59
+ name: section.title,
60
+ content: section.content,
61
+ types: [],
62
+ extends: extends_,
63
+ sectionRef: section.id,
64
+ };
65
+ }
66
+ /**
67
+ * Parse attributes from local def content
68
+ * Looks for:
69
+ * 1. Fenced blocks with "yaml busy" or "json busy"
70
+ * 2. Inline patterns like "Extends: [...]" or "_Extends:_"
71
+ */
72
+ function parseLocalDefAttrs(content) {
73
+ const attrs = {};
74
+ let extends_ = [];
75
+ // Check for fenced blocks first
76
+ const yamlBusyMatch = content.match(/```(?:yaml|json)\s+busy\s*\n([\s\S]*?)```/);
77
+ if (yamlBusyMatch) {
78
+ try {
79
+ // Simple parsing - just look for key: value pairs
80
+ const block = yamlBusyMatch[1];
81
+ const lines = block.split('\n');
82
+ for (const line of lines) {
83
+ const match = line.match(/^\s*(\w+):\s*(.+)$/);
84
+ if (match) {
85
+ const [, key, value] = match;
86
+ // Try to parse as JSON
87
+ try {
88
+ attrs[key] = JSON.parse(value);
89
+ }
90
+ catch {
91
+ attrs[key] = value.trim();
92
+ }
93
+ }
94
+ }
95
+ if (attrs.Extends) {
96
+ extends_ = Array.isArray(attrs.Extends)
97
+ ? attrs.Extends
98
+ : [attrs.Extends];
99
+ }
100
+ }
101
+ catch (err) {
102
+ debug.localdefs('Failed to parse fenced block: %s', err);
103
+ }
104
+ }
105
+ // Look for inline Extends patterns
106
+ const extendsPatterns = [
107
+ /^Extends:\s*\[(.*?)\]/im,
108
+ /^_Extends:_\s*\[(.*?)\]/im,
109
+ /^Extends:\s*(.+)$/im,
110
+ ];
111
+ for (const pattern of extendsPatterns) {
112
+ const match = content.match(pattern);
113
+ if (match) {
114
+ const value = match[1].trim();
115
+ // Parse as comma-separated list or JSON array
116
+ try {
117
+ const parsed = JSON.parse(`[${value}]`);
118
+ extends_ = [...extends_, ...parsed];
119
+ }
120
+ catch {
121
+ // Try comma-separated
122
+ extends_ = [
123
+ ...extends_,
124
+ ...value.split(',').map((s) => s.trim().replace(/['"]/g, '')),
125
+ ];
126
+ }
127
+ break;
128
+ }
129
+ }
130
+ return { attrs, extends: Array.from(new Set(extends_)) };
131
+ }
132
+ //# sourceMappingURL=localdefs.js.map
@@ -0,0 +1,32 @@
1
+ import { Section, LegacyOperation, DocId, Step, Checklist, NewOperation } from '../types/schema.js';
2
+ /**
3
+ * Parse numbered steps from markdown content
4
+ * Returns Step objects with stepNumber, instruction, and operationReferences
5
+ *
6
+ * @param content - Markdown content to parse
7
+ * @returns Array of Step objects
8
+ */
9
+ export declare function parseSteps(content: string): Step[];
10
+ /**
11
+ * Parse checklist items from markdown content
12
+ * Returns Checklist object with items array, or null if no checklist found
13
+ *
14
+ * @param content - Markdown content to parse
15
+ * @returns Checklist object or null
16
+ */
17
+ export declare function parseChecklist(content: string): Checklist | null;
18
+ /**
19
+ * Parse operations from markdown content
20
+ * Returns array of Operation objects matching busy-python format
21
+ *
22
+ * @param content - Full markdown document content
23
+ * @returns Array of NewOperation objects
24
+ */
25
+ export declare function parseOperations(content: string): NewOperation[];
26
+ type Operation = LegacyOperation;
27
+ /**
28
+ * Extract Operations from sections
29
+ */
30
+ export declare function extractOperations(sections: Section[], docId: DocId, filePath: string): Operation[];
31
+ export {};
32
+ //# sourceMappingURL=operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/parsers/operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAapG;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,CAsClD;AA2BD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CA2ChE;AA8BD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CAqD/D;AAOD,KAAK,SAAS,GAAG,eAAe,CAAC;AAEjC;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,GACf,SAAS,EAAE,CAmCb"}