@meza/adr-tools 1.0.8 → 1.0.11
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/.gitattributes +40 -0
- package/.github/renovate.json +5 -0
- package/.github/workflows/ci-pr.yml +44 -0
- package/.github/workflows/ci.yml +21 -22
- package/.github/workflows/sync-deps-to-main.yml +25 -0
- package/.github/workflows/sync-to-deps.yml +26 -0
- package/.releaserc.json +2 -7
- package/CHANGELOG.md +84 -0
- package/LICENSE +674 -0
- package/README.md +64 -5
- package/biome.json +148 -0
- package/dist/index.js +105 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/adr.js +177 -0
- package/dist/lib/adr.js.map +1 -0
- package/dist/lib/config.js +33 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/links.js +25 -0
- package/dist/lib/links.js.map +1 -0
- package/dist/lib/links.test.js +65 -0
- package/dist/lib/links.test.js.map +1 -0
- package/dist/lib/manipulator.js +84 -0
- package/dist/lib/manipulator.js.map +1 -0
- package/dist/lib/manipulator.test.js +76 -0
- package/dist/lib/manipulator.test.js.map +1 -0
- package/dist/lib/numbering.js +25 -0
- package/dist/lib/numbering.js.map +1 -0
- package/dist/lib/numbering.test.js +32 -0
- package/dist/lib/numbering.test.js.map +1 -0
- package/dist/lib/prompt.js +14 -0
- package/dist/lib/prompt.js.map +1 -0
- package/dist/lib/prompt.test.js +33 -0
- package/dist/lib/prompt.test.js.map +1 -0
- package/dist/lib/template.js +21 -0
- package/dist/lib/template.js.map +1 -0
- package/{doc/adr/0001-record-architecture-decisions.md → dist/templates/init.md} +2 -2
- package/dist/templates/template.md +19 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/lib/adr.d.ts +18 -0
- package/dist/types/lib/adr.d.ts.map +1 -0
- package/dist/types/lib/config.d.ts +3 -0
- package/dist/types/lib/config.d.ts.map +1 -0
- package/dist/types/lib/links.d.ts +10 -0
- package/dist/types/lib/links.d.ts.map +1 -0
- package/dist/types/lib/links.test.d.ts +2 -0
- package/dist/types/lib/links.test.d.ts.map +1 -0
- package/dist/types/lib/manipulator.d.ts +11 -0
- package/dist/types/lib/manipulator.d.ts.map +1 -0
- package/dist/types/lib/manipulator.test.d.ts +2 -0
- package/dist/types/lib/manipulator.test.d.ts.map +1 -0
- package/dist/types/lib/numbering.d.ts +2 -0
- package/dist/types/lib/numbering.d.ts.map +1 -0
- package/dist/types/lib/numbering.test.d.ts +2 -0
- package/dist/types/lib/numbering.test.d.ts.map +1 -0
- package/dist/types/lib/prompt.d.ts +2 -0
- package/dist/types/lib/prompt.d.ts.map +1 -0
- package/dist/types/lib/prompt.test.d.ts +2 -0
- package/dist/types/lib/prompt.test.d.ts.map +1 -0
- package/dist/types/lib/template.d.ts +2 -0
- package/dist/types/lib/template.d.ts.map +1 -0
- package/dist/types/version.d.ts +2 -0
- package/dist/types/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/doc/adr/.adr-sequence.lock +1 -0
- package/doc/adr/decisions.md +3 -0
- package/package.json +78 -48
- package/src/index.ts +52 -27
- package/src/lib/adr.ts +67 -72
- package/src/lib/config.ts +3 -3
- package/src/lib/links.test.ts +8 -24
- package/src/lib/links.ts +2 -2
- package/src/lib/manipulator.test.ts +44 -47
- package/src/lib/manipulator.ts +22 -10
- package/src/lib/numbering.test.ts +5 -9
- package/src/lib/numbering.ts +4 -5
- package/src/lib/prompt.test.ts +42 -0
- package/src/lib/prompt.ts +14 -0
- package/src/lib/template.ts +7 -3
- package/src/version.ts +1 -1
- package/tests/.adr-dir +1 -0
- package/tests/__snapshots__/generate-graph.e2e.test.ts.snap +23 -23
- package/tests/__snapshots__/init-adr-repository.e2e.test.ts.snap +1 -1
- package/tests/__snapshots__/linking-records.e2e.test.ts.snap +1 -1
- package/tests/__snapshots__/new-adr.e2e.test.ts.snap +1 -1
- package/tests/__snapshots__/superseding-records.e2e.test.ts.snap +1 -1
- package/tests/__snapshots__/toc-prefixing.e2e.test.ts.snap +1 -1
- package/tests/__snapshots__/use-template-override.e2e.test.ts.snap +1 -1
- package/tests/edit-on-create.e2e.test.ts +17 -12
- package/tests/funny-characters.e2e.test.ts +28 -21
- package/tests/generate-graph.e2e.test.ts +21 -13
- package/tests/init-adr-repository.e2e.test.ts +12 -8
- package/tests/linking-records.e2e.test.ts +21 -14
- package/tests/list-adrs.e2e.test.ts +23 -18
- package/tests/new-adr.e2e.test.ts +15 -12
- package/tests/superseding-records.e2e.test.ts +16 -11
- package/tests/toc-prefixing.e2e.test.ts +15 -11
- package/tests/use-template-override.e2e.test.ts +18 -10
- package/tests/work-form-other-directories.e2e.test.ts +14 -12
- package/tsconfig.json +9 -8
- package/vitest.config.e2e.ts +13 -0
- package/vitest.config.ts +8 -1
- package/.eslintignore +0 -2
- package/.eslintrc.json +0 -23
- package/.github/dependabot.yml +0 -14
- package/.github/workflows/auto-merge.yml +0 -14
- package/doc/adr/0002-using-heavy-e2e-tests.md +0 -20
- /package/src/{environment.d.ts → types/environment.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,14 +1,73 @@
|
|
|
1
1
|
# ADR-TOOLS
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> This is a Typescript fork of Nat Pryce's [ADR-TOOLS](https://github.com/npryce/adr-tools).
|
|
4
|
+
>There are a few other forks out there which do some parts of the original tool but none actually do it fully.
|
|
5
|
+
>This does.
|
|
6
|
+
>More documentation to follow very soon!
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
# Using ADRs
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
If you’re interested in reading more about what ADRs are and why they’re important, [check this article out](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions).
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
## **ADR Location Convention**
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
By convention we store the decisions in **<project_root>/docs/decisions**
|
|
15
|
+
|
|
16
|
+
You can also check where the directory is by inspecting the **.adr-dir** file’s contents.
|
|
17
|
+
|
|
18
|
+
## **ADR CLI in node land**
|
|
19
|
+
|
|
20
|
+
Managing the files and templates by hand is laborious and is not expected from anyone. We have a tool capable of handling that.
|
|
21
|
+
|
|
22
|
+
You can install it by running
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
npm install --save-dev @meza/adr-tools
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This will give you the following shorthands:
|
|
29
|
+
|
|
30
|
+
### **Creating new records**
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
adr new A new decision the team has made
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This will automatically figure out the numbering sequence, get the correct filename format and use the title inside of an ADR template.
|
|
37
|
+
|
|
38
|
+
If you have an EDITOR or VISUAL environment variable set, that editor will open the newly created file.
|
|
39
|
+
|
|
40
|
+
### **Superseding previous decisions**
|
|
41
|
+
|
|
42
|
+
We work in an agile environment where we aim to fail fast. Some of our decisions will turn out to be invalid within a new context. In those situations we would want to record a new decision to supersede our previous one.
|
|
43
|
+
|
|
44
|
+
Let’s say we had a decision “[0003-use-jest-for-testing.md](http://0003-use-jest-for-testing.md/)” but we recently learned that vitest is faster. Then we would want to record that but also update 0003 to reflect the fact that it’s no longer valid.
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
adr new -s 3 Use vitest for testing
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The -s flag tells the tool to update record #3 with a link to the newly created decision.
|
|
51
|
+
|
|
52
|
+
### **Linking decisions**
|
|
53
|
+
|
|
54
|
+
Sometimes there are situations when a new decision has another type of link to a previous record and not a supersede.
|
|
55
|
+
|
|
56
|
+
That can be expressed as follows:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
adr new -l "3:Amends:Amended by" use jest only for pact testing
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This will link the new and old issues together. The old one will get a link looking like “Amended by: Use jest only for pact testing” while the newly created ADR will have a section saying: “Amends: Use Jest For Testing”. Both with the appropriate numbering and navigational links set up.
|
|
63
|
+
|
|
64
|
+
### **Other things**
|
|
65
|
+
|
|
66
|
+
There’s more to the tool. You can get help with
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
adr help
|
|
70
|
+
```
|
|
12
71
|
|
|
13
72
|
## Conventions
|
|
14
73
|
|
package/biome.json
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
|
|
3
|
+
"organizeImports": { "enabled": true },
|
|
4
|
+
"vcs": {
|
|
5
|
+
"enabled": false,
|
|
6
|
+
"clientKind": "git",
|
|
7
|
+
"useIgnoreFile": true,
|
|
8
|
+
"defaultBranch": "main"
|
|
9
|
+
},
|
|
10
|
+
"formatter": {
|
|
11
|
+
"enabled": true,
|
|
12
|
+
"indentStyle": "space",
|
|
13
|
+
"indentWidth": 2,
|
|
14
|
+
"lineWidth": 120,
|
|
15
|
+
"lineEnding": "lf",
|
|
16
|
+
"include": ["**/*.ts", "**/*.json"],
|
|
17
|
+
"ignore": [".cache/**"],
|
|
18
|
+
"attributePosition": "auto"
|
|
19
|
+
},
|
|
20
|
+
"files": { "include": ["**/*.ts", "**/*.json"], "ignore": ["package*.json"] },
|
|
21
|
+
"linter": {
|
|
22
|
+
"enabled": true,
|
|
23
|
+
"rules": {
|
|
24
|
+
"recommended": false,
|
|
25
|
+
"complexity": {
|
|
26
|
+
"noBannedTypes": "error",
|
|
27
|
+
"noExtraBooleanCast": "error",
|
|
28
|
+
"noMultipleSpacesInRegularExpressionLiterals": "error",
|
|
29
|
+
"noUselessCatch": "error",
|
|
30
|
+
"noUselessLoneBlockStatements": "error",
|
|
31
|
+
"noUselessTernary": "error",
|
|
32
|
+
"noUselessThisAlias": "error",
|
|
33
|
+
"noUselessTypeConstraint": "error",
|
|
34
|
+
"noVoid": "error",
|
|
35
|
+
"noWith": "error",
|
|
36
|
+
"useArrowFunction": "error",
|
|
37
|
+
"useLiteralKeys": "error"
|
|
38
|
+
},
|
|
39
|
+
"correctness": {
|
|
40
|
+
"noConstAssign": "error",
|
|
41
|
+
"noConstantCondition": "error",
|
|
42
|
+
"noEmptyCharacterClassInRegex": "error",
|
|
43
|
+
"noEmptyPattern": "error",
|
|
44
|
+
"noGlobalObjectCalls": "error",
|
|
45
|
+
"noInnerDeclarations": "error",
|
|
46
|
+
"noInvalidConstructorSuper": "error",
|
|
47
|
+
"noInvalidUseBeforeDeclaration": "error",
|
|
48
|
+
"noNewSymbol": "error",
|
|
49
|
+
"noNonoctalDecimalEscape": "error",
|
|
50
|
+
"noPrecisionLoss": "error",
|
|
51
|
+
"noSelfAssign": "error",
|
|
52
|
+
"noSetterReturn": "error",
|
|
53
|
+
"noSwitchDeclarations": "error",
|
|
54
|
+
"noUndeclaredVariables": "error",
|
|
55
|
+
"noUnreachable": "error",
|
|
56
|
+
"noUnreachableSuper": "error",
|
|
57
|
+
"noUnsafeFinally": "error",
|
|
58
|
+
"noUnsafeOptionalChaining": "error",
|
|
59
|
+
"noUnusedLabels": "error",
|
|
60
|
+
"noUnusedVariables": "error",
|
|
61
|
+
"useArrayLiterals": "off",
|
|
62
|
+
"useIsNan": "error",
|
|
63
|
+
"useValidForDirection": "error",
|
|
64
|
+
"useYield": "error"
|
|
65
|
+
},
|
|
66
|
+
"security": { "noGlobalEval": "error" },
|
|
67
|
+
"style": {
|
|
68
|
+
"noCommaOperator": "error",
|
|
69
|
+
"noNamespace": "off",
|
|
70
|
+
"noParameterAssign": "error",
|
|
71
|
+
"noUselessElse": "error",
|
|
72
|
+
"noVar": "off",
|
|
73
|
+
"useAsConstAssertion": "error",
|
|
74
|
+
"useBlockStatements": "error",
|
|
75
|
+
"useCollapsedElseIf": "error",
|
|
76
|
+
"useConst": "error",
|
|
77
|
+
"useShorthandAssign": "error",
|
|
78
|
+
"useSingleVarDeclarator": "off"
|
|
79
|
+
},
|
|
80
|
+
"suspicious": {
|
|
81
|
+
"noAssignInExpressions": "error",
|
|
82
|
+
"noAsyncPromiseExecutor": "error",
|
|
83
|
+
"noCatchAssign": "error",
|
|
84
|
+
"noClassAssign": "error",
|
|
85
|
+
"noCompareNegZero": "error",
|
|
86
|
+
"noConfusingLabels": "error",
|
|
87
|
+
"noConsoleLog": "off",
|
|
88
|
+
"noControlCharactersInRegex": "error",
|
|
89
|
+
"noDebugger": "error",
|
|
90
|
+
"noDoubleEquals": "error",
|
|
91
|
+
"noDuplicateCase": "error",
|
|
92
|
+
"noDuplicateClassMembers": "error",
|
|
93
|
+
"noDuplicateObjectKeys": "error",
|
|
94
|
+
"noDuplicateParameters": "error",
|
|
95
|
+
"noEmptyBlockStatements": "error",
|
|
96
|
+
"noExplicitAny": "error",
|
|
97
|
+
"noExtraNonNullAssertion": "error",
|
|
98
|
+
"noFallthroughSwitchClause": "error",
|
|
99
|
+
"noFunctionAssign": "error",
|
|
100
|
+
"noGlobalAssign": "error",
|
|
101
|
+
"noImportAssign": "error",
|
|
102
|
+
"noLabelVar": "error",
|
|
103
|
+
"noMisleadingCharacterClass": "error",
|
|
104
|
+
"noMisleadingInstantiator": "error",
|
|
105
|
+
"noPrototypeBuiltins": "error",
|
|
106
|
+
"noRedeclare": "error",
|
|
107
|
+
"noSelfCompare": "error",
|
|
108
|
+
"noShadowRestrictedNames": "error",
|
|
109
|
+
"noUnsafeDeclarationMerging": "error",
|
|
110
|
+
"noUnsafeNegation": "error",
|
|
111
|
+
"useGetterReturn": "error",
|
|
112
|
+
"useValidTypeof": "error"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"ignore": ["**/node_modules", "**/dist", "lib/murmurhash3.ts"]
|
|
116
|
+
},
|
|
117
|
+
"json": {
|
|
118
|
+
"formatter": {
|
|
119
|
+
"trailingCommas": "none",
|
|
120
|
+
"enabled": true
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"javascript": {
|
|
124
|
+
"formatter": {
|
|
125
|
+
"quoteStyle": "single",
|
|
126
|
+
"enabled": true,
|
|
127
|
+
"semicolons": "always",
|
|
128
|
+
"quoteProperties": "asNeeded",
|
|
129
|
+
"trailingCommas": "none",
|
|
130
|
+
"bracketSpacing": true,
|
|
131
|
+
"bracketSameLine": true,
|
|
132
|
+
"attributePosition": "auto"
|
|
133
|
+
},
|
|
134
|
+
"globals": []
|
|
135
|
+
},
|
|
136
|
+
"overrides": [
|
|
137
|
+
{
|
|
138
|
+
"include": ["**/*.test.ts", "test/**/*.ts"],
|
|
139
|
+
"linter": {
|
|
140
|
+
"rules": {
|
|
141
|
+
"correctness": { "noInvalidUseBeforeDeclaration": "off" },
|
|
142
|
+
"style": { "noNonNullAssertion": "off" },
|
|
143
|
+
"suspicious": { "noEmptyBlockStatements": "off", "noExplicitAny": "off" }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import fs from 'fs/promises';
|
|
6
|
+
import { generateToc, init, link, listAdrs, newAdr } from './lib/adr.js';
|
|
7
|
+
import { workingDir } from './lib/config.js';
|
|
8
|
+
import { getLinksFrom, getTitleFrom } from './lib/manipulator.js';
|
|
9
|
+
import { LIB_VERSION } from './version.js';
|
|
10
|
+
const program = new Command();
|
|
11
|
+
const collectLinks = (val, memo) => {
|
|
12
|
+
memo.push(val);
|
|
13
|
+
return memo;
|
|
14
|
+
};
|
|
15
|
+
const collectSupersedes = (val, memo) => {
|
|
16
|
+
memo.push(val);
|
|
17
|
+
return memo;
|
|
18
|
+
};
|
|
19
|
+
const generateGraph = async (options) => {
|
|
20
|
+
let text = 'digraph {\n';
|
|
21
|
+
text += ' node [shape=plaintext];\n';
|
|
22
|
+
text += ' subgraph {\n';
|
|
23
|
+
const adrs = await listAdrs();
|
|
24
|
+
for (let i = 0; i < adrs.length; i++) {
|
|
25
|
+
const n = i + 1;
|
|
26
|
+
const adrPath = adrs[i];
|
|
27
|
+
const contents = await fs.readFile(adrPath, 'utf8');
|
|
28
|
+
const title = getTitleFrom(contents);
|
|
29
|
+
text += ` _${n} [label="${title}"; URL="${options?.prefix || ''}${path.basename(adrPath, '.md')}${options?.extension}"];\n`;
|
|
30
|
+
if (n > 1) {
|
|
31
|
+
text += ` _${n - 1} -> _${n} [style="dotted", weight=1];\n`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
text += ' }\n';
|
|
35
|
+
for (let i = 0; i < adrs.length; i++) {
|
|
36
|
+
const n = i + 1;
|
|
37
|
+
const adrPath = adrs[i];
|
|
38
|
+
const contents = await fs.readFile(adrPath, 'utf8');
|
|
39
|
+
const linksInADR = getLinksFrom(contents);
|
|
40
|
+
for (let j = 0; j < linksInADR.length; j++) {
|
|
41
|
+
if (!linksInADR[j].label.endsWith('by')) {
|
|
42
|
+
text += ` _${n} -> _${linksInADR[j].targetNumber} [label="${linksInADR[j].label}", weight=0]\n`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
text += '}\n';
|
|
47
|
+
console.log(text);
|
|
48
|
+
};
|
|
49
|
+
program.name('adr').version(LIB_VERSION).description('Manage Architecture Decision Logs');
|
|
50
|
+
program
|
|
51
|
+
.command('new')
|
|
52
|
+
.argument('<title...>', 'The title of the decision')
|
|
53
|
+
.option('-q, --quiet', 'Do not ask for clarification. If multiple files match the search pattern, an error will be thrown.')
|
|
54
|
+
.option('-s, --supersede <SUPERSEDE>', 'A reference (number or partial filename) of a previous decision that the new decision supercedes.\n' +
|
|
55
|
+
'A Markdown link to the superceded ADR is inserted into the Status section.\n' +
|
|
56
|
+
'The status of the superceded ADR is changed to record that it has been superceded by the new ADR.', collectSupersedes, [])
|
|
57
|
+
.option('-l, --link "<TARGET:LINK:REVERSE-LINK>"', 'Links the new ADR to a previous ADR.\n' +
|
|
58
|
+
`${chalk.bold('TARGET')} is a reference (number or partial filename) of a previous decision.\n` +
|
|
59
|
+
`${chalk.bold('LINK')} is the description of the link created in the new ADR.\n` +
|
|
60
|
+
`${chalk.bold('REVERSE-LINK')} is the description of the link created in the existing ADR that will refer to the new ADR`, collectLinks, [])
|
|
61
|
+
.action(async (title, options) => {
|
|
62
|
+
try {
|
|
63
|
+
await newAdr(title.join(' '), {
|
|
64
|
+
supersedes: options.supersede,
|
|
65
|
+
date: process.env.ADR_DATE,
|
|
66
|
+
suppressPrompts: options.quiet || false,
|
|
67
|
+
links: options.link
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
program.error(chalk.red(e.message), { exitCode: 1 });
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
const generate = program.command('generate');
|
|
75
|
+
generate
|
|
76
|
+
.command('toc')
|
|
77
|
+
.option('-p, --prefix <PREFIX>', 'The prefix to use for each file link in the generated TOC.')
|
|
78
|
+
.action((options) => generateToc(options));
|
|
79
|
+
generate
|
|
80
|
+
.command('graph')
|
|
81
|
+
.option('-p, --prefix <PREFIX>', 'Prefix each decision file link with PREFIX.')
|
|
82
|
+
.option('-e, --extension <EXTENSION>', 'the file extension of the documents to which generated links refer. Defaults to .html', '.html')
|
|
83
|
+
.action(async (options) => {
|
|
84
|
+
await generateGraph(options);
|
|
85
|
+
});
|
|
86
|
+
program
|
|
87
|
+
.command('link')
|
|
88
|
+
.argument('<SOURCE>', 'Full or Partial reference number to an ADR')
|
|
89
|
+
.argument('<LINK>', 'The description of the link created in the SOURCE')
|
|
90
|
+
.argument('<TARGET>', 'Full or Partial reference number to an ADR')
|
|
91
|
+
.argument('<REVERSE-LINK>', 'The description of the link created in the TARGET')
|
|
92
|
+
.option('-q, --quiet', 'Do not ask for clarification. If multiple files match the search pattern, an error will be thrown.')
|
|
93
|
+
.action(link);
|
|
94
|
+
program
|
|
95
|
+
.command('init')
|
|
96
|
+
.argument('[directory]', 'Initialize a new ADR directory')
|
|
97
|
+
.action(async (directory) => {
|
|
98
|
+
await init(directory);
|
|
99
|
+
});
|
|
100
|
+
program.command('list').action(async () => {
|
|
101
|
+
const adrs = await listAdrs();
|
|
102
|
+
console.log(adrs.map((adr) => path.relative(workingDir(), adr)).join('\n'));
|
|
103
|
+
});
|
|
104
|
+
program.parse();
|
|
105
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"src/","sources":["index.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/adr.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import childProcess from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import fs from 'fs/promises';
|
|
5
|
+
import { getDir, workingDir } from './config.js';
|
|
6
|
+
import { findMatchingFilesFor, getLinkDetails } from './links.js';
|
|
7
|
+
import { getTitleFrom, injectLink, supersede } from './manipulator.js';
|
|
8
|
+
import { newNumber } from './numbering.js';
|
|
9
|
+
import { askForClarification } from './prompt.js';
|
|
10
|
+
import { template } from './template.js';
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
// eslint-disable-next-line no-unused-vars
|
|
13
|
+
var LinkType;
|
|
14
|
+
(function (LinkType) {
|
|
15
|
+
// eslint-disable-next-line no-unused-vars
|
|
16
|
+
LinkType["LINK"] = "link";
|
|
17
|
+
// eslint-disable-next-line no-unused-vars
|
|
18
|
+
LinkType["SUPERSEDE"] = "supersede";
|
|
19
|
+
})(LinkType || (LinkType = {}));
|
|
20
|
+
const actuallyLink = async (task) => {
|
|
21
|
+
const linkedFile = path.join(await getDir(), task.targetPath);
|
|
22
|
+
const newAdrContent = await fs.readFile(task.sourcePath, 'utf8');
|
|
23
|
+
const oldAdrContent = await fs.readFile(linkedFile, 'utf8');
|
|
24
|
+
const oldTitle = getTitleFrom(oldAdrContent);
|
|
25
|
+
const newTitle = getTitleFrom(newAdrContent);
|
|
26
|
+
let dirtyOld = '', dirtyNew = '';
|
|
27
|
+
switch (task.type) {
|
|
28
|
+
case LinkType.LINK:
|
|
29
|
+
dirtyOld = injectLink(oldAdrContent, `${task.reverseLink} [${newTitle}](${path.relative(await getDir(), task.sourcePath)})`);
|
|
30
|
+
dirtyNew = injectLink(newAdrContent, `${task.link} [${oldTitle}](${task.targetPath})`);
|
|
31
|
+
break;
|
|
32
|
+
case LinkType.SUPERSEDE:
|
|
33
|
+
dirtyOld = supersede(oldAdrContent, `${task.reverseLink} [${newTitle}](${path.relative(await getDir(), task.sourcePath)})`);
|
|
34
|
+
dirtyNew = injectLink(newAdrContent, `${task.link} [${oldTitle}](${task.targetPath})`);
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
await fs.writeFile(linkedFile, dirtyOld);
|
|
40
|
+
await fs.writeFile(task.sourcePath, dirtyNew);
|
|
41
|
+
};
|
|
42
|
+
const processSupersedes = async (sourcePath, supersedes = [], suppressPrompts = false) => {
|
|
43
|
+
if (supersedes.length === 0) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const supersedeStrings = await Promise.all(supersedes.map((link) => getLinkDetails(link, true)));
|
|
47
|
+
for (const targetDetails of supersedeStrings) {
|
|
48
|
+
const task = {
|
|
49
|
+
type: LinkType.SUPERSEDE,
|
|
50
|
+
sourcePath: sourcePath,
|
|
51
|
+
link: targetDetails.link,
|
|
52
|
+
reverseLink: targetDetails.reverseLink,
|
|
53
|
+
targetPath: targetDetails.matches[0]
|
|
54
|
+
};
|
|
55
|
+
if (targetDetails.matches.length > 1) {
|
|
56
|
+
if (suppressPrompts) {
|
|
57
|
+
throw new Error(`Multiple files match the search pattern for "${targetDetails.original}".\n` +
|
|
58
|
+
'Please specify which file you want to targetDetails to more or remove the -q or --quiet options from the command line.');
|
|
59
|
+
}
|
|
60
|
+
task.targetPath = await askForClarification(targetDetails.original, targetDetails.matches);
|
|
61
|
+
}
|
|
62
|
+
await actuallyLink(task);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const injectLinksTo = async (sourcePath, links = [], suppressPrompts = false) => {
|
|
66
|
+
if (links.length === 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const linkStrings = await Promise.all(links.map((link) => getLinkDetails(link)));
|
|
70
|
+
for (const targetDetails of linkStrings) {
|
|
71
|
+
const task = {
|
|
72
|
+
type: LinkType.LINK,
|
|
73
|
+
sourcePath: sourcePath,
|
|
74
|
+
link: targetDetails.link,
|
|
75
|
+
reverseLink: targetDetails.reverseLink,
|
|
76
|
+
targetPath: targetDetails.matches[0]
|
|
77
|
+
};
|
|
78
|
+
if (targetDetails.matches.length > 1) {
|
|
79
|
+
if (suppressPrompts) {
|
|
80
|
+
throw new Error(`Multiple files match the search pattern for "${targetDetails.original}".\n` +
|
|
81
|
+
'Please specify which file you want to targetDetails to more or remove the -q or --quiet options from the command line.');
|
|
82
|
+
}
|
|
83
|
+
task.targetPath = await askForClarification(targetDetails.original, targetDetails.matches);
|
|
84
|
+
}
|
|
85
|
+
await actuallyLink(task);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
//Generate a table of contents for the adr directory
|
|
89
|
+
export const generateToc = async (options) => {
|
|
90
|
+
const adrDir = await getDir();
|
|
91
|
+
const files = await fs.readdir(adrDir);
|
|
92
|
+
const toc = files.filter((file) => file.match(/^\d{4}-.*\.md$/));
|
|
93
|
+
const titles = toc.map(async (file) => {
|
|
94
|
+
const title = getTitleFrom(await fs.readFile(path.join(adrDir, file), 'utf8'));
|
|
95
|
+
return `- [${title}](${options?.prefix || ''}${file})`;
|
|
96
|
+
});
|
|
97
|
+
const resolvedTitles = await Promise.all(titles);
|
|
98
|
+
const tocFile = path.resolve(path.join(adrDir, 'decisions.md'));
|
|
99
|
+
await fs.writeFile(tocFile, `# Table of Contents\n\n${resolvedTitles.join('\n')}`);
|
|
100
|
+
};
|
|
101
|
+
export const newAdr = async (title, config) => {
|
|
102
|
+
const newNum = await newNumber();
|
|
103
|
+
const formattedDate = config?.date || new Date().toISOString().split('T')[0] || 'ERROR';
|
|
104
|
+
const tpl = await template(config?.template);
|
|
105
|
+
const adr = tpl
|
|
106
|
+
.replace('DATE', formattedDate)
|
|
107
|
+
.replace('TITLE', title)
|
|
108
|
+
.replace('NUMBER', newNum.toString())
|
|
109
|
+
.replace('STATUS', 'Accepted');
|
|
110
|
+
const paddedNumber = newNum.toString().padStart(4, '0');
|
|
111
|
+
const cleansedTitle = title
|
|
112
|
+
.toLowerCase()
|
|
113
|
+
.replace(/\W/g, '-')
|
|
114
|
+
.replace(/^(.*)\W$/, '$1')
|
|
115
|
+
.replace(/^\W(.*)$/, '$1');
|
|
116
|
+
const fileName = `${paddedNumber}-${cleansedTitle}.md`;
|
|
117
|
+
const adrDirectory = await getDir();
|
|
118
|
+
const adrPath = path.resolve(path.join(adrDirectory, fileName));
|
|
119
|
+
await fs.writeFile(adrPath, adr);
|
|
120
|
+
await fs.writeFile(path.resolve(adrDirectory, '.adr-sequence.lock'), newNum.toString());
|
|
121
|
+
await processSupersedes(adrPath, config?.supersedes, config?.suppressPrompts);
|
|
122
|
+
await injectLinksTo(adrPath, config?.links, config?.suppressPrompts);
|
|
123
|
+
await generateToc();
|
|
124
|
+
if (process.env.VISUAL) {
|
|
125
|
+
await childProcess.spawn(process.env.VISUAL, [adrPath], {
|
|
126
|
+
stdio: 'inherit',
|
|
127
|
+
shell: true
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (process.env.EDITOR) {
|
|
132
|
+
await childProcess.spawn(process.env.EDITOR, [adrPath], {
|
|
133
|
+
stdio: 'inherit',
|
|
134
|
+
shell: true
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
export const init = async (directory) => {
|
|
140
|
+
const dir = directory || (await getDir());
|
|
141
|
+
await fs.mkdir(dir, { recursive: true });
|
|
142
|
+
await fs.writeFile(path.join(workingDir(), '.adr-dir'), path.relative(workingDir(), dir));
|
|
143
|
+
await newAdr('Record Architecture Decisions', {
|
|
144
|
+
date: process.env.ADR_DATE,
|
|
145
|
+
template: path.resolve(path.dirname(__filename), '../templates/init.md')
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
export const link = async (source, link, target, reverseLink, options) => {
|
|
149
|
+
const getFor = async (pattern) => {
|
|
150
|
+
const found = await findMatchingFilesFor(pattern);
|
|
151
|
+
if (found.length === 1) {
|
|
152
|
+
return found[0];
|
|
153
|
+
}
|
|
154
|
+
if (options?.quiet) {
|
|
155
|
+
throw new Error(`Multiple files match the search pattern for "${pattern}".\n` +
|
|
156
|
+
'Please specify which file you want to targetDetails to more or remove the -q or --quiet options from the command line.');
|
|
157
|
+
}
|
|
158
|
+
return askForClarification(pattern, found);
|
|
159
|
+
};
|
|
160
|
+
const sourceFile = await getFor(source);
|
|
161
|
+
await injectLinksTo(path.resolve(await getDir(), sourceFile), [`${target}:${link}:${reverseLink}`]);
|
|
162
|
+
};
|
|
163
|
+
export const listAdrs = async () => {
|
|
164
|
+
const dir = await getDir();
|
|
165
|
+
const files = await fs.readdir(dir);
|
|
166
|
+
const toc = files
|
|
167
|
+
.map((f) => {
|
|
168
|
+
const adrFile = f.match(/^0*(\d+)-.*$/);
|
|
169
|
+
if (adrFile) {
|
|
170
|
+
return path.resolve(dir, adrFile[0]);
|
|
171
|
+
}
|
|
172
|
+
return '';
|
|
173
|
+
})
|
|
174
|
+
.filter((f) => f !== '');
|
|
175
|
+
return toc;
|
|
176
|
+
};
|
|
177
|
+
//# sourceMappingURL=adr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adr.js","sourceRoot":"src/","sources":["lib/adr.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { constants } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
export const workingDir = () => process.cwd();
|
|
5
|
+
const findTopLevelDir = async (dir) => {
|
|
6
|
+
try {
|
|
7
|
+
await fs.access(path.join(dir, '.adr-dir'), constants.F_OK);
|
|
8
|
+
return dir;
|
|
9
|
+
}
|
|
10
|
+
catch (_e) {
|
|
11
|
+
if (dir === '/') {
|
|
12
|
+
throw new Error('No ADR directory config found');
|
|
13
|
+
}
|
|
14
|
+
const newDir = path.join(dir, '..');
|
|
15
|
+
return findTopLevelDir(newDir);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const getDirPath = async () => {
|
|
19
|
+
try {
|
|
20
|
+
const configDir = await findTopLevelDir(workingDir());
|
|
21
|
+
const configFile = await fs.readFile(path.join(configDir, '.adr-dir'), 'utf8');
|
|
22
|
+
return path.relative(workingDir(), path.join(configDir, configFile.trim()));
|
|
23
|
+
}
|
|
24
|
+
catch (_e) {
|
|
25
|
+
return path.resolve(path.join(workingDir(), 'doc/adr'));
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export const getDir = async () => {
|
|
29
|
+
const dir = await getDirPath();
|
|
30
|
+
await fs.mkdir(dir, { recursive: true });
|
|
31
|
+
return dir;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"src/","sources":["lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,aAAa,CAAC;AAE7B,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;AAE9C,MAAM,eAAe,GAAG,KAAK,EAAE,GAAW,EAAmB,EAAE;IAC7D,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5D,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACZ,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACpC,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,KAAK,IAAqB,EAAE;IAC7C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,UAAU,EAAE,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9E,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,IAAqB,EAAE;IAChD,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import { getDir } from './config.js';
|
|
3
|
+
export const findMatchingFilesFor = async (pattern) => {
|
|
4
|
+
const files = await fs.readdir(await getDir());
|
|
5
|
+
return files.filter((file) => file.includes(pattern));
|
|
6
|
+
};
|
|
7
|
+
export const getLinkDetails = async (linkString, isSupersede = false) => {
|
|
8
|
+
const parts = linkString.split(':');
|
|
9
|
+
const pattern = parts[0];
|
|
10
|
+
let link = 'Supersedes';
|
|
11
|
+
let reverseLink = 'Superseded by';
|
|
12
|
+
if (!isSupersede) {
|
|
13
|
+
link = parts[1];
|
|
14
|
+
reverseLink = parts[2];
|
|
15
|
+
}
|
|
16
|
+
const files = await findMatchingFilesFor(pattern);
|
|
17
|
+
return {
|
|
18
|
+
pattern: pattern,
|
|
19
|
+
original: linkString,
|
|
20
|
+
link: link,
|
|
21
|
+
reverseLink: reverseLink,
|
|
22
|
+
matches: files
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.js","sourceRoot":"src/","sources":["lib/links.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAUrC,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,OAAe,EAAE,EAAE;IAC5D,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,UAAkB,EAAE,cAAuB,KAAK,EAAwB,EAAE;IAC7G,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,IAAI,GAAG,YAAY,CAAC;IACxB,IAAI,WAAW,GAAG,eAAe,CAAC;IAClC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAChB,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAClD,OAAO;QACL,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,WAAW;QACxB,OAAO,EAAE,KAAK;KACf,CAAC;AACJ,CAAC,CAAC"}
|