xdrs-core 0.15.0 → 0.15.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.
|
@@ -36,6 +36,7 @@ Collectively, these are referred to as XDRs.
|
|
|
36
36
|
- ALWAYS use the following folder structure for XDR documents:
|
|
37
37
|
`.xdrs/[scope]/[type]/[subject]/[number]-[short-title].md`
|
|
38
38
|
- ALWAYS ignore symlinks paths. NEVER create or update documents inside symlinked folders.
|
|
39
|
+
- **Readonly files are external XDRs.** A file with read-only permissions (e.g., `444` set by a distribution tool such as filedist) was distributed from an external source repository. It must NEVER be modified locally. To change it, submit the change to the source repository and re-extract the updated package.
|
|
39
40
|
- Optional supporting artifacts under the same subject:
|
|
40
41
|
- `.xdrs/[scope]/[type]/[subject]/researches/[number]-[short-title].md`
|
|
41
42
|
- `.xdrs/[scope]/[type]/[subject]/skills/[number]-[skill-name]/SKILL.md`
|
|
@@ -77,12 +77,14 @@ Choose a title that clearly states the question this XDR answers, not the answer
|
|
|
77
77
|
Use the mandatory template from `002-xdr-standards`:
|
|
78
78
|
|
|
79
79
|
```
|
|
80
|
-
|
|
80
|
+
---
|
|
81
|
+
name: [scope]-[type]-[number]-[short-title]
|
|
82
|
+
description: [What this decision is about and when to use it]
|
|
83
|
+
applied-to: [Optional. Contexts this decision applies to, under 40 words]
|
|
84
|
+
valid-from: [Optional. ISO date YYYY-MM-DD from when enforcement begins]
|
|
85
|
+
---
|
|
81
86
|
|
|
82
|
-
|
|
83
|
-
[Optional. Include only when at least one metadata field is present]
|
|
84
|
-
Valid: [Optional. Use from YYYY-MM-DD to set a convergence date for adoption]
|
|
85
|
-
Applied to: [Optional short applicability scope, under 40 words]
|
|
87
|
+
# [scope]-[type]-[number]: [Short Title]
|
|
86
88
|
|
|
87
89
|
## Context and Problem Statement
|
|
88
90
|
[background, who is impacted, and the explicit question being answered - under 40 words]
|
|
@@ -103,10 +105,10 @@ Applied to: [Optional short applicability scope, under 40 words]
|
|
|
103
105
|
```
|
|
104
106
|
|
|
105
107
|
Mandatory rules to apply while drafting:
|
|
106
|
-
- Include
|
|
107
|
-
-
|
|
108
|
-
- Keep `
|
|
109
|
-
- When metadata is present, write it so a reader can decide whether the XDR should be used for the current case without guessing. `
|
|
108
|
+
- Include frontmatter `applied-to:` only when it adds value by narrowing the decision scope; omit it when the decision applies broadly.
|
|
109
|
+
- Include frontmatter `valid-from:` only when there is a specific future enforcement date; omit it when the decision is immediately effective.
|
|
110
|
+
- Keep `applied-to:` under 40 words and use `valid-from:` only with `YYYY-MM-DD` ISO format.
|
|
111
|
+
- When frontmatter metadata is present, write it so a reader can decide whether the XDR should be used for the current case without guessing. `valid-from:` sets a convergence date for adoption, `applied-to:` narrows the contexts where the decision applies, and the decision text defines any remaining boundaries.
|
|
110
112
|
- Use mandatory language ("must", "always", "never") only for hard requirements; use advisory language ("should", "recommended") for guidance.
|
|
111
113
|
- Do not duplicate content already in referenced XDRs — link instead.
|
|
112
114
|
- Keep the decision itself authoritative in the XDR. Supporting artifacts may elaborate, but they should not restate the full decision when a short reference is enough.
|
|
@@ -122,7 +124,7 @@ Mandatory rules to apply while drafting:
|
|
|
122
124
|
Check every item before finalizing:
|
|
123
125
|
|
|
124
126
|
1. **Length**: Is it under 1300 words? Trim verbose explanations. Move detailed skills to a separate file and link.
|
|
125
|
-
2. **
|
|
127
|
+
2. **Frontmatter**: Are `applied-to:` and `valid-from:` present only when they add value, omitted entirely when not needed, and specific enough for a reader to decide whether the XDR is currently valid and applicable?
|
|
126
128
|
3. **Originality**: Does every sentence add value that cannot be found in a generic web search? Remove obvious advice. Keep only the project-specific decision.
|
|
127
129
|
4. **Clarity**: Is the chosen option unambiguous? Is the "why" clear in one reading?
|
|
128
130
|
5. **Redundancy**: Is the XDR the primary source for the decision itself, with related documents linked instead of duplicated wherever possible?
|
package/lib/lint.js
CHANGED
|
@@ -31,8 +31,10 @@ function runLintCli(args) {
|
|
|
31
31
|
return 0;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const
|
|
35
|
-
const
|
|
34
|
+
const all = args.includes('--all');
|
|
35
|
+
const pathArgs = args.filter((a) => !a.startsWith('--'));
|
|
36
|
+
const targetPath = pathArgs[0] || '.';
|
|
37
|
+
const result = lintWorkspace(targetPath, { ignoreReadOnly: !all });
|
|
36
38
|
|
|
37
39
|
if (result.errors.length === 0) {
|
|
38
40
|
console.log(`Lint passed for ${toDisplayPath(result.xdrsRoot)}`);
|
|
@@ -48,12 +50,15 @@ function runLintCli(args) {
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
function printHelp() {
|
|
51
|
-
console.log('Usage: xdrs-core lint [path]\n');
|
|
53
|
+
console.log('Usage: xdrs-core lint [options] [path]\n');
|
|
52
54
|
console.log('Lint the XDR tree rooted at [path]/.xdrs or at [path] when [path] already points to .xdrs.');
|
|
53
|
-
console.log('
|
|
55
|
+
console.log('\nOptions:');
|
|
56
|
+
console.log(' --all Check all files, including read-only files from other scopes (default: skip read-only files)');
|
|
57
|
+
console.log('\nAll other commands continue to be delegated to the bundled filedist CLI.');
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
function lintWorkspace(targetPath) {
|
|
60
|
+
function lintWorkspace(targetPath, options = {}) {
|
|
61
|
+
const { ignoreReadOnly = true } = options;
|
|
57
62
|
const resolvedTarget = path.resolve(targetPath);
|
|
58
63
|
const xdrsRoot = path.basename(resolvedTarget) === '.xdrs'
|
|
59
64
|
? resolvedTarget
|
|
@@ -76,7 +81,7 @@ function lintWorkspace(targetPath) {
|
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
for (const scopeEntry of scopeEntries) {
|
|
79
|
-
lintScopeDirectory(xdrsRoot, scopeEntry.name, errors, actualTypeIndexes);
|
|
84
|
+
lintScopeDirectory(xdrsRoot, scopeEntry.name, errors, actualTypeIndexes, ignoreReadOnly);
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
const rootIndexPath = path.join(xdrsRoot, 'index.md');
|
|
@@ -124,9 +129,13 @@ function lintRootIndex(rootIndexPath, xdrsRoot, actualTypeIndexes, errors) {
|
|
|
124
129
|
}
|
|
125
130
|
}
|
|
126
131
|
|
|
127
|
-
function lintScopeDirectory(xdrsRoot, scopeName, errors, actualTypeIndexes) {
|
|
132
|
+
function lintScopeDirectory(xdrsRoot, scopeName, errors, actualTypeIndexes, ignoreReadOnly) {
|
|
128
133
|
const scopePath = path.join(xdrsRoot, scopeName);
|
|
129
134
|
|
|
135
|
+
if (ignoreReadOnly && isReadOnly(scopePath)) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
130
139
|
if (!isValidScopeName(scopeName)) {
|
|
131
140
|
errors.push(`Invalid scope name: ${toDisplayPath(scopePath)}`);
|
|
132
141
|
}
|
|
@@ -744,6 +753,15 @@ function existsFile(filePath) {
|
|
|
744
753
|
}
|
|
745
754
|
}
|
|
746
755
|
|
|
756
|
+
function isReadOnly(filePath) {
|
|
757
|
+
try {
|
|
758
|
+
fs.accessSync(filePath, fs.constants.W_OK);
|
|
759
|
+
return false;
|
|
760
|
+
} catch {
|
|
761
|
+
return true;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
747
765
|
function displayPath(indexPath, targetPath) {
|
|
748
766
|
return `${toDisplayPath(indexPath)} -> ${toDisplayPath(targetPath)}`;
|
|
749
767
|
}
|
package/package.json
CHANGED