@joshski/dust 0.1.100 → 0.1.101

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 (68) hide show
  1. package/.dust/principles/actionable-errors.md +18 -0
  2. package/.dust/principles/agent-agnostic-design.md +21 -0
  3. package/.dust/principles/agent-autonomy.md +19 -0
  4. package/.dust/principles/agent-context-inference.md +19 -0
  5. package/.dust/principles/agent-specific-enhancement.md +23 -0
  6. package/.dust/principles/atomic-commits.md +15 -0
  7. package/.dust/principles/batteries-included.md +17 -0
  8. package/.dust/principles/boy-scout-rule.md +15 -0
  9. package/.dust/principles/broken-windows.md +17 -0
  10. package/.dust/principles/clarity-over-brevity.md +13 -0
  11. package/.dust/principles/co-located-tests.md +13 -0
  12. package/.dust/principles/comprehensive-assertions.md +50 -0
  13. package/.dust/principles/comprehensive-test-coverage.md +15 -0
  14. package/.dust/principles/consistent-naming.md +13 -0
  15. package/.dust/principles/context-optimised-code.md +15 -0
  16. package/.dust/principles/context-window-efficiency.md +15 -0
  17. package/.dust/principles/cross-platform-compatibility.md +19 -0
  18. package/.dust/principles/debugging-tooling.md +19 -0
  19. package/.dust/principles/decoupled-code.md +16 -0
  20. package/.dust/principles/dependency-injection.md +15 -0
  21. package/.dust/principles/design-for-testability.md +17 -0
  22. package/.dust/principles/development-traceability.md +19 -0
  23. package/.dust/principles/easy-adoption.md +17 -0
  24. package/.dust/principles/enable-flow-state.md +20 -0
  25. package/.dust/principles/environment-independent-tests.md +19 -0
  26. package/.dust/principles/exploratory-tooling.md +19 -0
  27. package/.dust/principles/fast-feedback-loops.md +15 -0
  28. package/.dust/principles/fast-feedback.md +13 -0
  29. package/.dust/principles/functional-core-imperative-shell.md +15 -0
  30. package/.dust/principles/human-ai-collaboration.md +18 -0
  31. package/.dust/principles/ideal-agent-developer-experience.md +24 -0
  32. package/.dust/principles/intuitive-directory-structure.md +13 -0
  33. package/.dust/principles/keep-unit-tests-pure.md +25 -0
  34. package/.dust/principles/lightweight-planning.md +16 -0
  35. package/.dust/principles/lint-everything.md +19 -0
  36. package/.dust/principles/maintainable-codebase.md +21 -0
  37. package/.dust/principles/make-changes-with-confidence.md +23 -0
  38. package/.dust/principles/make-the-change-easy.md +15 -0
  39. package/.dust/principles/minimal-dependencies.md +13 -0
  40. package/.dust/principles/naming-matters.md +14 -0
  41. package/.dust/principles/progressive-disclosure.md +15 -0
  42. package/.dust/principles/readable-test-data.md +48 -0
  43. package/.dust/principles/reasonably-dry.md +13 -0
  44. package/.dust/principles/repository-hygiene.md +14 -0
  45. package/.dust/principles/reproducible-checks.md +13 -0
  46. package/.dust/principles/runtime-agnostic-tests.md +13 -0
  47. package/.dust/principles/self-contained-repository.md +17 -0
  48. package/.dust/principles/self-diagnosing-tests.md +54 -0
  49. package/.dust/principles/slow-feedback-coping.md +15 -0
  50. package/.dust/principles/small-units.md +17 -0
  51. package/.dust/principles/some-big-design-up-front.md +34 -0
  52. package/.dust/principles/stop-the-line.md +13 -0
  53. package/.dust/principles/stubs-over-mocks.md +19 -0
  54. package/.dust/principles/task-first-workflow.md +13 -0
  55. package/.dust/principles/test-isolation.md +19 -0
  56. package/.dust/principles/traceable-decisions.md +13 -0
  57. package/.dust/principles/trunk-based-development.md +19 -0
  58. package/.dust/principles/unit-test-coverage.md +13 -0
  59. package/.dust/principles/unsurprising-ux.md +15 -0
  60. package/.dust/principles/vcs-independence.md +13 -0
  61. package/dist/bucket/repository.d.ts +28 -0
  62. package/dist/cli/types.d.ts +1 -0
  63. package/dist/core-principles.js +184 -0
  64. package/dist/dust.js +470 -54
  65. package/dist/lint/validators/principle-hierarchy.d.ts +0 -1
  66. package/dist/patch/index.d.ts +8 -0
  67. package/dist/patch.js +54 -1
  68. package/package.json +7 -2
@@ -0,0 +1,184 @@
1
+ // lib/core-principles.ts
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { existsSync, readdirSync, statSync } from "node:fs";
5
+ import { readFile } from "node:fs/promises";
6
+
7
+ // lib/markdown/markdown-utilities.ts
8
+ function extractTitle(content) {
9
+ const match = content.match(/^#\s+(.+)$/m);
10
+ return match ? match[1].trim() : null;
11
+ }
12
+ var MARKDOWN_LINK_PATTERN = /\[([^\]]+)\]\(([^)]+)\)/;
13
+
14
+ // lib/artifacts/principles.ts
15
+ function extractLinksFromSection(content, sectionHeading) {
16
+ const lines = content.split(`
17
+ `);
18
+ const links = [];
19
+ let inSection = false;
20
+ for (const line of lines) {
21
+ if (line.startsWith("## ")) {
22
+ inSection = line.trimEnd() === `## ${sectionHeading}`;
23
+ continue;
24
+ }
25
+ if (!inSection)
26
+ continue;
27
+ if (line.startsWith("# "))
28
+ break;
29
+ const linkMatch = line.match(MARKDOWN_LINK_PATTERN);
30
+ if (linkMatch) {
31
+ const target = linkMatch[2];
32
+ const slugMatch = target.match(/([^/]+)\.md$/);
33
+ if (slugMatch) {
34
+ links.push(slugMatch[1]);
35
+ }
36
+ }
37
+ }
38
+ return links;
39
+ }
40
+ function extractSingleLinkFromSection(content, sectionHeading) {
41
+ const links = extractLinksFromSection(content, sectionHeading);
42
+ return links.length === 1 ? links[0] : null;
43
+ }
44
+ async function parsePrinciple(fileSystem, dustPath, slug) {
45
+ const principlePath = `${dustPath}/principles/${slug}.md`;
46
+ if (!fileSystem.exists(principlePath)) {
47
+ throw new Error(`Principle not found: "${slug}" (expected file at ${principlePath})`);
48
+ }
49
+ const content = await fileSystem.readFile(principlePath);
50
+ const title = extractTitle(content);
51
+ if (!title) {
52
+ throw new Error(`Principle file has no title: ${principlePath}`);
53
+ }
54
+ const parentPrinciple = extractSingleLinkFromSection(content, "Parent Principle");
55
+ const subPrinciples = extractLinksFromSection(content, "Sub-Principles");
56
+ return {
57
+ slug,
58
+ title,
59
+ content,
60
+ parentPrinciple,
61
+ subPrinciples
62
+ };
63
+ }
64
+
65
+ // lib/artifacts/core-principles.ts
66
+ function sortNodes(nodes) {
67
+ nodes.sort((a, b) => a.title.localeCompare(b.title));
68
+ for (const node of nodes) {
69
+ sortNodes(node.children);
70
+ }
71
+ }
72
+ function isInternalPrinciple(principleContent) {
73
+ const lines = principleContent.split(`
74
+ `);
75
+ let inApplicabilitySection = false;
76
+ for (const line of lines) {
77
+ if (line.startsWith("## ")) {
78
+ inApplicabilitySection = line.trimEnd() === "## Applicability";
79
+ continue;
80
+ }
81
+ if (inApplicabilitySection) {
82
+ if (line.startsWith("# "))
83
+ break;
84
+ if (line.trim() === "Internal") {
85
+ return true;
86
+ }
87
+ }
88
+ }
89
+ return false;
90
+ }
91
+ function listCorePrinciples(allPrinciples, config) {
92
+ const excludeSet = new Set(config.excludeCorePrinciples ?? []);
93
+ return allPrinciples.filter((p) => !isInternalPrinciple(p.content) && !excludeSet.has(p.slug)).map((p) => p.slug).toSorted();
94
+ }
95
+ function getCorePrincipleTree(allPrinciples, config) {
96
+ const excludeSet = new Set(config.excludeCorePrinciples ?? []);
97
+ const filteredPrinciples = allPrinciples.filter((p) => !isInternalPrinciple(p.content) && !excludeSet.has(p.slug));
98
+ const filteredSlugs = new Set(filteredPrinciples.map((p) => p.slug));
99
+ const nodeBySlug = new Map;
100
+ for (const p of filteredPrinciples) {
101
+ nodeBySlug.set(p.slug, {
102
+ slug: p.slug,
103
+ title: p.title,
104
+ children: []
105
+ });
106
+ }
107
+ const roots = [];
108
+ for (const p of filteredPrinciples) {
109
+ const node = nodeBySlug.get(p.slug);
110
+ const parentSlug = p.parentPrinciple;
111
+ if (!parentSlug || !filteredSlugs.has(parentSlug)) {
112
+ roots.push(node);
113
+ } else {
114
+ const parentNode = nodeBySlug.get(parentSlug);
115
+ if (parentNode) {
116
+ parentNode.children.push(node);
117
+ }
118
+ }
119
+ }
120
+ sortNodes(roots);
121
+ return roots;
122
+ }
123
+
124
+ // lib/core-principles.ts
125
+ function createReadableFileSystem() {
126
+ return {
127
+ exists: existsSync,
128
+ isDirectory: (path) => {
129
+ try {
130
+ return statSync(path).isDirectory();
131
+ } catch {
132
+ return false;
133
+ }
134
+ },
135
+ readFile: (path) => readFile(path, "utf-8"),
136
+ readdir: async (path) => readdirSync(path)
137
+ };
138
+ }
139
+ function locatePackagePrinciplesDir() {
140
+ const thisFile = fileURLToPath(import.meta.url);
141
+ const thisDir = dirname(thisFile);
142
+ const packageRoot = dirname(thisDir);
143
+ const principlesDir = join(packageRoot, ".dust", "principles");
144
+ if (!existsSync(principlesDir)) {
145
+ throw new Error(`Core principles directory not found at ${principlesDir}. ` + "Ensure the @joshski/dust package is properly installed.");
146
+ }
147
+ return principlesDir;
148
+ }
149
+ async function readAllCorePrinciples() {
150
+ const principlesDir = locatePackagePrinciplesDir();
151
+ const packageRoot = dirname(dirname(principlesDir));
152
+ const dustPath = join(packageRoot, ".dust");
153
+ const fileSystem = createReadableFileSystem();
154
+ const files = readdirSync(principlesDir);
155
+ const mdFiles = files.filter((f) => f.endsWith(".md"));
156
+ const principles = [];
157
+ for (const file of mdFiles) {
158
+ const slug = file.replace(/\.md$/, "");
159
+ const principle = await parsePrinciple(fileSystem, dustPath, slug);
160
+ principles.push(principle);
161
+ }
162
+ return principles;
163
+ }
164
+ async function getCorePrincipleSlugs(config = {}) {
165
+ const allPrinciples = await readAllCorePrinciples();
166
+ return listCorePrinciples(allPrinciples, config);
167
+ }
168
+ async function getCorePrincipleHierarchy(config = {}) {
169
+ const allPrinciples = await readAllCorePrinciples();
170
+ return getCorePrincipleTree(allPrinciples, config);
171
+ }
172
+ function getCorePrinciplesPath() {
173
+ const principlesDir = locatePackagePrinciplesDir();
174
+ return `${principlesDir}/`;
175
+ }
176
+ export {
177
+ readAllCorePrinciples,
178
+ listCorePrinciples,
179
+ isInternalPrinciple,
180
+ getCorePrinciplesPath,
181
+ getCorePrincipleTree,
182
+ getCorePrincipleSlugs,
183
+ getCorePrincipleHierarchy
184
+ };