@joshski/dust 0.1.109 → 0.1.110
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/dist/audits.js +163 -0
- package/dist/dust.js +167 -2
- package/dist/patch.js +5 -4
- package/dist/validation.js +5 -4
- package/package.json +1 -1
package/dist/audits.js
CHANGED
|
@@ -1865,6 +1865,168 @@ function slowTests() {
|
|
|
1865
1865
|
- No changes to files outside \`.dust/\`
|
|
1866
1866
|
`;
|
|
1867
1867
|
}
|
|
1868
|
+
function overAbstraction() {
|
|
1869
|
+
return dedent`
|
|
1870
|
+
# Over-Abstraction
|
|
1871
|
+
|
|
1872
|
+
Identify violations of the "reasonably-dry" principle where code has been over-engineered with excessive abstraction.
|
|
1873
|
+
|
|
1874
|
+
${ideasHint}
|
|
1875
|
+
|
|
1876
|
+
## Scope
|
|
1877
|
+
|
|
1878
|
+
Detect these over-abstraction patterns:
|
|
1879
|
+
|
|
1880
|
+
1. **Single-use abstractions** - Interfaces, base classes, or utility functions used in only one place
|
|
1881
|
+
2. **Deep inheritance hierarchies** - Classes extending more than 2 levels deep
|
|
1882
|
+
3. **Premature generalization** - Parameters always used with the same value, unused options/flags
|
|
1883
|
+
4. **Excessive indirection** - Multiple layers of wrappers adding no value
|
|
1884
|
+
|
|
1885
|
+
## Analysis Steps
|
|
1886
|
+
|
|
1887
|
+
### 1. Find Single-Use Abstractions
|
|
1888
|
+
|
|
1889
|
+
Search for abstractions that are only used once:
|
|
1890
|
+
|
|
1891
|
+
1. **Interfaces with one implementation**
|
|
1892
|
+
- Search for \`interface\` declarations
|
|
1893
|
+
- Check if each interface has only one implementing class
|
|
1894
|
+
- Flag interfaces that exist solely for testing (can be replaced with the concrete type)
|
|
1895
|
+
|
|
1896
|
+
2. **Base classes with one subclass**
|
|
1897
|
+
- Search for \`abstract class\` or classes used as base classes
|
|
1898
|
+
- Count implementations extending each base class
|
|
1899
|
+
- Flag base classes with only one subclass
|
|
1900
|
+
|
|
1901
|
+
3. **Utility functions called once**
|
|
1902
|
+
- Search for exported utility functions
|
|
1903
|
+
- Check call sites - if only called from one location, it's over-abstraction
|
|
1904
|
+
- Consider inlining single-use utilities
|
|
1905
|
+
|
|
1906
|
+
4. **Generic types with one concrete usage**
|
|
1907
|
+
- Find generic type parameters: \`<T>\`, \`<TData>\`, etc.
|
|
1908
|
+
- Check if T is always the same type at all call sites
|
|
1909
|
+
- Flag generics that could be concrete types
|
|
1910
|
+
|
|
1911
|
+
### 2. Detect Deep Inheritance Hierarchies
|
|
1912
|
+
|
|
1913
|
+
Find inheritance chains longer than 2 levels:
|
|
1914
|
+
|
|
1915
|
+
1. Search for \`extends\` keywords in class declarations
|
|
1916
|
+
2. Build inheritance tree for each class
|
|
1917
|
+
3. Flag chains deeper than 2 (A extends B extends C extends D...)
|
|
1918
|
+
4. Respect framework conventions (don't flag React.Component, etc.)
|
|
1919
|
+
|
|
1920
|
+
### 3. Identify Premature Generalization
|
|
1921
|
+
|
|
1922
|
+
Look for flexibility that's never used:
|
|
1923
|
+
|
|
1924
|
+
1. **Always-same parameter values**
|
|
1925
|
+
- Find function parameters
|
|
1926
|
+
- Check all call sites - if always the same value, it's not needed
|
|
1927
|
+
- Flag parameters that could be constants or removed
|
|
1928
|
+
|
|
1929
|
+
2. **Unused configuration options**
|
|
1930
|
+
- Search for configuration objects/interfaces
|
|
1931
|
+
- Check which options are actually used
|
|
1932
|
+
- Flag options that are never set or always default
|
|
1933
|
+
|
|
1934
|
+
3. **Unused function parameters**
|
|
1935
|
+
- Find parameters that aren't referenced in function bodies
|
|
1936
|
+
- Flag as candidates for removal
|
|
1937
|
+
|
|
1938
|
+
### 4. Find Excessive Indirection
|
|
1939
|
+
|
|
1940
|
+
Detect wrapper chains that add no value:
|
|
1941
|
+
|
|
1942
|
+
1. **Delegation chains**
|
|
1943
|
+
- Search for functions that only call another function
|
|
1944
|
+
- Flag wrappers that don't add logic, just forward calls
|
|
1945
|
+
- Example: \`function foo(x) { return bar(x) }\`
|
|
1946
|
+
|
|
1947
|
+
2. **Proxy patterns without behavior**
|
|
1948
|
+
- Find classes that wrap another class
|
|
1949
|
+
- Check if wrapper adds any logic beyond forwarding
|
|
1950
|
+
- Flag pure proxies
|
|
1951
|
+
|
|
1952
|
+
3. **Middleware without transformation**
|
|
1953
|
+
- Look for middleware/interceptor patterns
|
|
1954
|
+
- Check if they modify data or just pass through
|
|
1955
|
+
- Flag pass-through middleware
|
|
1956
|
+
|
|
1957
|
+
## Output Format
|
|
1958
|
+
|
|
1959
|
+
For each over-abstraction found, create an idea file in \`.dust/ideas/\` with:
|
|
1960
|
+
|
|
1961
|
+
\`\`\`markdown
|
|
1962
|
+
# Over-Abstraction: [Type] in [Location]
|
|
1963
|
+
|
|
1964
|
+
## Type
|
|
1965
|
+
|
|
1966
|
+
[Single-use | Deep hierarchy | Premature generalization | Excessive indirection]
|
|
1967
|
+
|
|
1968
|
+
## Location
|
|
1969
|
+
|
|
1970
|
+
\`\`\`
|
|
1971
|
+
[file path]:[line number]
|
|
1972
|
+
\`\`\`
|
|
1973
|
+
|
|
1974
|
+
## Description
|
|
1975
|
+
|
|
1976
|
+
[What the abstraction is]
|
|
1977
|
+
|
|
1978
|
+
## Problem
|
|
1979
|
+
|
|
1980
|
+
[Why this is over-abstraction - complexity without benefit]
|
|
1981
|
+
|
|
1982
|
+
## Usage Analysis
|
|
1983
|
+
|
|
1984
|
+
- **Times used**: [count]
|
|
1985
|
+
- **Variation in usage**: [how different are the use cases]
|
|
1986
|
+
- **Complexity cost**: [lines of code, indirection levels, etc.]
|
|
1987
|
+
|
|
1988
|
+
## Suggested Simplification
|
|
1989
|
+
|
|
1990
|
+
[How to remove or reduce this abstraction]
|
|
1991
|
+
|
|
1992
|
+
## Impact
|
|
1993
|
+
|
|
1994
|
+
[Lines of code saved, reduced complexity, improved clarity]
|
|
1995
|
+
\`\`\`
|
|
1996
|
+
|
|
1997
|
+
## Special Considerations
|
|
1998
|
+
|
|
1999
|
+
1. **Framework conventions** - Don't flag patterns mandated by frameworks:
|
|
2000
|
+
- React: Component base classes, hooks patterns
|
|
2001
|
+
- Express: Middleware signatures
|
|
2002
|
+
- Testing: Test base classes, fixture patterns
|
|
2003
|
+
|
|
2004
|
+
2. **Library boundaries** - Public API abstractions may be justified even if internal usage is simple
|
|
2005
|
+
|
|
2006
|
+
3. **Test code** - Apply the same standards to test code as production code
|
|
2007
|
+
|
|
2008
|
+
4. **Context depth thresholds**:
|
|
2009
|
+
- Deep hierarchies (>2 levels) make understanding difficult
|
|
2010
|
+
- Wrapper chains (>2 levels) obscure actual behavior
|
|
2011
|
+
- Generic parameters should have multiple concrete usages
|
|
2012
|
+
|
|
2013
|
+
## Blocked By
|
|
2014
|
+
|
|
2015
|
+
(none)
|
|
2016
|
+
|
|
2017
|
+
## Definition of Done
|
|
2018
|
+
|
|
2019
|
+
- Searched for single-use interfaces, base classes, and utility functions
|
|
2020
|
+
- Identified deep inheritance hierarchies (>2 levels)
|
|
2021
|
+
- Found parameters always used with the same value
|
|
2022
|
+
- Detected unused configuration options
|
|
2023
|
+
- Located excessive wrapper chains and delegation
|
|
2024
|
+
- Respected framework conventions (didn't flag framework-mandated patterns)
|
|
2025
|
+
- Created idea files for each over-abstraction found
|
|
2026
|
+
- Each idea includes usage analysis and simplification suggestions
|
|
2027
|
+
- No changes to files outside \`.dust/\`
|
|
2028
|
+
`;
|
|
2029
|
+
}
|
|
1868
2030
|
function primitiveObsession() {
|
|
1869
2031
|
return dedent`
|
|
1870
2032
|
# Primitive Obsession
|
|
@@ -3240,6 +3402,7 @@ var stockAuditFunctions = {
|
|
|
3240
3402
|
"idiomatic-style": idiomaticStyle,
|
|
3241
3403
|
"incidental-test-details": incidentalTestDetails,
|
|
3242
3404
|
"logging-and-traceability": loggingAndTraceability,
|
|
3405
|
+
"over-abstraction": overAbstraction,
|
|
3243
3406
|
"primitive-obsession": primitiveObsession,
|
|
3244
3407
|
"repository-context": repositoryContext,
|
|
3245
3408
|
"security-review": securityReview,
|
package/dist/dust.js
CHANGED
|
@@ -7,7 +7,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
7
7
|
var require_package = __commonJS((exports, module) => {
|
|
8
8
|
module.exports = {
|
|
9
9
|
name: "@joshski/dust",
|
|
10
|
-
version: "0.1.
|
|
10
|
+
version: "0.1.110",
|
|
11
11
|
description: "Flow state for AI coding agents",
|
|
12
12
|
type: "module",
|
|
13
13
|
bin: {
|
|
@@ -721,7 +721,7 @@ async function loadSettings(cwd, fileSystem, runtime) {
|
|
|
721
721
|
}
|
|
722
722
|
|
|
723
723
|
// lib/version.ts
|
|
724
|
-
var DUST_VERSION = "0.1.
|
|
724
|
+
var DUST_VERSION = "0.1.110";
|
|
725
725
|
|
|
726
726
|
// lib/cli/middleware.ts
|
|
727
727
|
function applyMiddleware(middlewares, execute) {
|
|
@@ -2895,6 +2895,168 @@ function slowTests() {
|
|
|
2895
2895
|
- No changes to files outside \`.dust/\`
|
|
2896
2896
|
`;
|
|
2897
2897
|
}
|
|
2898
|
+
function overAbstraction() {
|
|
2899
|
+
return dedent`
|
|
2900
|
+
# Over-Abstraction
|
|
2901
|
+
|
|
2902
|
+
Identify violations of the "reasonably-dry" principle where code has been over-engineered with excessive abstraction.
|
|
2903
|
+
|
|
2904
|
+
${ideasHint}
|
|
2905
|
+
|
|
2906
|
+
## Scope
|
|
2907
|
+
|
|
2908
|
+
Detect these over-abstraction patterns:
|
|
2909
|
+
|
|
2910
|
+
1. **Single-use abstractions** - Interfaces, base classes, or utility functions used in only one place
|
|
2911
|
+
2. **Deep inheritance hierarchies** - Classes extending more than 2 levels deep
|
|
2912
|
+
3. **Premature generalization** - Parameters always used with the same value, unused options/flags
|
|
2913
|
+
4. **Excessive indirection** - Multiple layers of wrappers adding no value
|
|
2914
|
+
|
|
2915
|
+
## Analysis Steps
|
|
2916
|
+
|
|
2917
|
+
### 1. Find Single-Use Abstractions
|
|
2918
|
+
|
|
2919
|
+
Search for abstractions that are only used once:
|
|
2920
|
+
|
|
2921
|
+
1. **Interfaces with one implementation**
|
|
2922
|
+
- Search for \`interface\` declarations
|
|
2923
|
+
- Check if each interface has only one implementing class
|
|
2924
|
+
- Flag interfaces that exist solely for testing (can be replaced with the concrete type)
|
|
2925
|
+
|
|
2926
|
+
2. **Base classes with one subclass**
|
|
2927
|
+
- Search for \`abstract class\` or classes used as base classes
|
|
2928
|
+
- Count implementations extending each base class
|
|
2929
|
+
- Flag base classes with only one subclass
|
|
2930
|
+
|
|
2931
|
+
3. **Utility functions called once**
|
|
2932
|
+
- Search for exported utility functions
|
|
2933
|
+
- Check call sites - if only called from one location, it's over-abstraction
|
|
2934
|
+
- Consider inlining single-use utilities
|
|
2935
|
+
|
|
2936
|
+
4. **Generic types with one concrete usage**
|
|
2937
|
+
- Find generic type parameters: \`<T>\`, \`<TData>\`, etc.
|
|
2938
|
+
- Check if T is always the same type at all call sites
|
|
2939
|
+
- Flag generics that could be concrete types
|
|
2940
|
+
|
|
2941
|
+
### 2. Detect Deep Inheritance Hierarchies
|
|
2942
|
+
|
|
2943
|
+
Find inheritance chains longer than 2 levels:
|
|
2944
|
+
|
|
2945
|
+
1. Search for \`extends\` keywords in class declarations
|
|
2946
|
+
2. Build inheritance tree for each class
|
|
2947
|
+
3. Flag chains deeper than 2 (A extends B extends C extends D...)
|
|
2948
|
+
4. Respect framework conventions (don't flag React.Component, etc.)
|
|
2949
|
+
|
|
2950
|
+
### 3. Identify Premature Generalization
|
|
2951
|
+
|
|
2952
|
+
Look for flexibility that's never used:
|
|
2953
|
+
|
|
2954
|
+
1. **Always-same parameter values**
|
|
2955
|
+
- Find function parameters
|
|
2956
|
+
- Check all call sites - if always the same value, it's not needed
|
|
2957
|
+
- Flag parameters that could be constants or removed
|
|
2958
|
+
|
|
2959
|
+
2. **Unused configuration options**
|
|
2960
|
+
- Search for configuration objects/interfaces
|
|
2961
|
+
- Check which options are actually used
|
|
2962
|
+
- Flag options that are never set or always default
|
|
2963
|
+
|
|
2964
|
+
3. **Unused function parameters**
|
|
2965
|
+
- Find parameters that aren't referenced in function bodies
|
|
2966
|
+
- Flag as candidates for removal
|
|
2967
|
+
|
|
2968
|
+
### 4. Find Excessive Indirection
|
|
2969
|
+
|
|
2970
|
+
Detect wrapper chains that add no value:
|
|
2971
|
+
|
|
2972
|
+
1. **Delegation chains**
|
|
2973
|
+
- Search for functions that only call another function
|
|
2974
|
+
- Flag wrappers that don't add logic, just forward calls
|
|
2975
|
+
- Example: \`function foo(x) { return bar(x) }\`
|
|
2976
|
+
|
|
2977
|
+
2. **Proxy patterns without behavior**
|
|
2978
|
+
- Find classes that wrap another class
|
|
2979
|
+
- Check if wrapper adds any logic beyond forwarding
|
|
2980
|
+
- Flag pure proxies
|
|
2981
|
+
|
|
2982
|
+
3. **Middleware without transformation**
|
|
2983
|
+
- Look for middleware/interceptor patterns
|
|
2984
|
+
- Check if they modify data or just pass through
|
|
2985
|
+
- Flag pass-through middleware
|
|
2986
|
+
|
|
2987
|
+
## Output Format
|
|
2988
|
+
|
|
2989
|
+
For each over-abstraction found, create an idea file in \`.dust/ideas/\` with:
|
|
2990
|
+
|
|
2991
|
+
\`\`\`markdown
|
|
2992
|
+
# Over-Abstraction: [Type] in [Location]
|
|
2993
|
+
|
|
2994
|
+
## Type
|
|
2995
|
+
|
|
2996
|
+
[Single-use | Deep hierarchy | Premature generalization | Excessive indirection]
|
|
2997
|
+
|
|
2998
|
+
## Location
|
|
2999
|
+
|
|
3000
|
+
\`\`\`
|
|
3001
|
+
[file path]:[line number]
|
|
3002
|
+
\`\`\`
|
|
3003
|
+
|
|
3004
|
+
## Description
|
|
3005
|
+
|
|
3006
|
+
[What the abstraction is]
|
|
3007
|
+
|
|
3008
|
+
## Problem
|
|
3009
|
+
|
|
3010
|
+
[Why this is over-abstraction - complexity without benefit]
|
|
3011
|
+
|
|
3012
|
+
## Usage Analysis
|
|
3013
|
+
|
|
3014
|
+
- **Times used**: [count]
|
|
3015
|
+
- **Variation in usage**: [how different are the use cases]
|
|
3016
|
+
- **Complexity cost**: [lines of code, indirection levels, etc.]
|
|
3017
|
+
|
|
3018
|
+
## Suggested Simplification
|
|
3019
|
+
|
|
3020
|
+
[How to remove or reduce this abstraction]
|
|
3021
|
+
|
|
3022
|
+
## Impact
|
|
3023
|
+
|
|
3024
|
+
[Lines of code saved, reduced complexity, improved clarity]
|
|
3025
|
+
\`\`\`
|
|
3026
|
+
|
|
3027
|
+
## Special Considerations
|
|
3028
|
+
|
|
3029
|
+
1. **Framework conventions** - Don't flag patterns mandated by frameworks:
|
|
3030
|
+
- React: Component base classes, hooks patterns
|
|
3031
|
+
- Express: Middleware signatures
|
|
3032
|
+
- Testing: Test base classes, fixture patterns
|
|
3033
|
+
|
|
3034
|
+
2. **Library boundaries** - Public API abstractions may be justified even if internal usage is simple
|
|
3035
|
+
|
|
3036
|
+
3. **Test code** - Apply the same standards to test code as production code
|
|
3037
|
+
|
|
3038
|
+
4. **Context depth thresholds**:
|
|
3039
|
+
- Deep hierarchies (>2 levels) make understanding difficult
|
|
3040
|
+
- Wrapper chains (>2 levels) obscure actual behavior
|
|
3041
|
+
- Generic parameters should have multiple concrete usages
|
|
3042
|
+
|
|
3043
|
+
## Blocked By
|
|
3044
|
+
|
|
3045
|
+
(none)
|
|
3046
|
+
|
|
3047
|
+
## Definition of Done
|
|
3048
|
+
|
|
3049
|
+
- Searched for single-use interfaces, base classes, and utility functions
|
|
3050
|
+
- Identified deep inheritance hierarchies (>2 levels)
|
|
3051
|
+
- Found parameters always used with the same value
|
|
3052
|
+
- Detected unused configuration options
|
|
3053
|
+
- Located excessive wrapper chains and delegation
|
|
3054
|
+
- Respected framework conventions (didn't flag framework-mandated patterns)
|
|
3055
|
+
- Created idea files for each over-abstraction found
|
|
3056
|
+
- Each idea includes usage analysis and simplification suggestions
|
|
3057
|
+
- No changes to files outside \`.dust/\`
|
|
3058
|
+
`;
|
|
3059
|
+
}
|
|
2898
3060
|
function primitiveObsession() {
|
|
2899
3061
|
return dedent`
|
|
2900
3062
|
# Primitive Obsession
|
|
@@ -4270,6 +4432,7 @@ var stockAuditFunctions = {
|
|
|
4270
4432
|
"idiomatic-style": idiomaticStyle,
|
|
4271
4433
|
"incidental-test-details": incidentalTestDetails,
|
|
4272
4434
|
"logging-and-traceability": loggingAndTraceability,
|
|
4435
|
+
"over-abstraction": overAbstraction,
|
|
4273
4436
|
"primitive-obsession": primitiveObsession,
|
|
4274
4437
|
"repository-context": repositoryContext,
|
|
4275
4438
|
"security-review": securityReview,
|
|
@@ -5754,6 +5917,8 @@ function buildImplementationInstructions(bin, hooksInstalled, taskTitle, taskPat
|
|
|
5754
5917
|
steps.push(`${step}. Run \`${bin} check\` to verify the project is in a good state`);
|
|
5755
5918
|
step++;
|
|
5756
5919
|
}
|
|
5920
|
+
steps.push(`${step}. If the task file contains Principles and Guidance sections, read and follow them before implementing changes`);
|
|
5921
|
+
step++;
|
|
5757
5922
|
steps.push(`${step}. Implement the task`);
|
|
5758
5923
|
step++;
|
|
5759
5924
|
if (!hooksInstalled) {
|
package/dist/patch.js
CHANGED
|
@@ -167,7 +167,7 @@ function isErrorCode(error, code) {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
// lib/validation/index.ts
|
|
170
|
-
import { relative } from "node:path";
|
|
170
|
+
import { relative, resolve as resolve3 } from "node:path";
|
|
171
171
|
|
|
172
172
|
// lib/validation/overlay-filesystem.ts
|
|
173
173
|
function createOverlayFileSystem(base, patchFiles, deletedPaths = new Set) {
|
|
@@ -1003,11 +1003,12 @@ function parsePatchFiles(dustPath, patch) {
|
|
|
1003
1003
|
}
|
|
1004
1004
|
async function validatePatch(fileSystem, dustPath, patch, options = {}) {
|
|
1005
1005
|
const cwd = options.cwd ?? process.cwd();
|
|
1006
|
-
const
|
|
1006
|
+
const resolvedDustPath = resolve3(dustPath);
|
|
1007
|
+
const { absolutePatchFiles, deletedPaths } = parsePatchFiles(resolvedDustPath, patch);
|
|
1007
1008
|
const overlayFs = createOverlayFileSystem(fileSystem, absolutePatchFiles, deletedPaths);
|
|
1008
1009
|
const violations = [];
|
|
1009
|
-
violations.push(...validatePatchRootEntries(fileSystem,
|
|
1010
|
-
const { context, violations: parseViolations } = await parseArtifacts(overlayFs,
|
|
1010
|
+
violations.push(...validatePatchRootEntries(fileSystem, resolvedDustPath, patch));
|
|
1011
|
+
const { context, violations: parseViolations } = await parseArtifacts(overlayFs, resolvedDustPath);
|
|
1011
1012
|
violations.push(...parseViolations);
|
|
1012
1013
|
violations.push(...validateArtifacts(context));
|
|
1013
1014
|
return {
|
package/dist/validation.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// lib/validation/index.ts
|
|
2
|
-
import { relative } from "node:path";
|
|
2
|
+
import { relative, resolve as resolve3 } from "node:path";
|
|
3
3
|
|
|
4
4
|
// lib/filesystem/error-codes.ts
|
|
5
5
|
function isErrnoException(error) {
|
|
@@ -1000,11 +1000,12 @@ function parsePatchFiles(dustPath, patch) {
|
|
|
1000
1000
|
}
|
|
1001
1001
|
async function validatePatch(fileSystem, dustPath, patch, options = {}) {
|
|
1002
1002
|
const cwd = options.cwd ?? process.cwd();
|
|
1003
|
-
const
|
|
1003
|
+
const resolvedDustPath = resolve3(dustPath);
|
|
1004
|
+
const { absolutePatchFiles, deletedPaths } = parsePatchFiles(resolvedDustPath, patch);
|
|
1004
1005
|
const overlayFs = createOverlayFileSystem(fileSystem, absolutePatchFiles, deletedPaths);
|
|
1005
1006
|
const violations = [];
|
|
1006
|
-
violations.push(...validatePatchRootEntries(fileSystem,
|
|
1007
|
-
const { context, violations: parseViolations } = await parseArtifacts(overlayFs,
|
|
1007
|
+
violations.push(...validatePatchRootEntries(fileSystem, resolvedDustPath, patch));
|
|
1008
|
+
const { context, violations: parseViolations } = await parseArtifacts(overlayFs, resolvedDustPath);
|
|
1008
1009
|
violations.push(...parseViolations);
|
|
1009
1010
|
violations.push(...validateArtifacts(context));
|
|
1010
1011
|
return {
|