@descent-vtt/spec-graph 0.19.0 → 0.20.0
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/CHANGELOG.md +68 -0
- package/README.md +28 -8
- package/dist/cli.js +34 -9
- package/dist/cli.js.map +1 -1
- package/dist/extract.js +36 -3
- package/dist/extract.js.map +1 -1
- package/dist/paths.d.ts +12 -0
- package/dist/paths.js +14 -0
- package/dist/paths.js.map +1 -1
- package/package.json +1 -1
package/dist/paths.js
CHANGED
|
@@ -40,6 +40,20 @@ const LOWER_DRIVE = /^(\\\\[?.]\\)?([a-z]):/;
|
|
|
40
40
|
export function foldDriveLetter(resolved) {
|
|
41
41
|
return resolved.replace(LOWER_DRIVE, (_drive, device, letter) => `${device ?? ''}${letter.toUpperCase()}:`);
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Whether a path the host resolved holds a `\` inside a name, on a host whose
|
|
45
|
+
* separator is `separator`.
|
|
46
|
+
*
|
|
47
|
+
* A root is read with each `\` a separator, as Windows writes one, so a root
|
|
48
|
+
* typed `docs\adr` is `docs/adr` on every host. Where the host's separator is
|
|
49
|
+
* `/`, a `\` it resolved, from the directory a run starts in, is a character
|
|
50
|
+
* of a name, and read as a separator it spells another directory: the walk,
|
|
51
|
+
* the configuration and a recorded baseline went there (ADR-0010,
|
|
52
|
+
* 2026-10-24). Where the separator is `\`, no name can hold one.
|
|
53
|
+
*/
|
|
54
|
+
export function holdsBackslashInName(resolved, separator) {
|
|
55
|
+
return separator === '/' && resolved.includes('\\');
|
|
56
|
+
}
|
|
43
57
|
/** Removes `.` and `..` segments. Leading `..` are preserved. */
|
|
44
58
|
export function normalisePosix(value) {
|
|
45
59
|
const absolute = value.startsWith('/');
|
package/dist/paths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * POSIX path arithmetic, independent of the host platform.\n *\n * Every path inside spec-graph is a repository-relative POSIX path, on Windows\n * as much as on Linux. Node's `path` module would happily produce\n * `docs\\adr\\0007.md` on one machine and `docs/adr/0007.md` on another, and a\n * graph whose node identities depend on which laptop built it is not a graph.\n */\n\n/** Converts a host path to POSIX form. */\nexport function toPosix(value: string): string {\n return value.replace(/\\\\/g, '/');\n}\n\nconst ABSOLUTE = /^(?:[/\\\\]|[A-Za-z]:)/;\n\n/**\n * Whether a path names a place outright rather than a place relative to one.\n *\n * Both platforms' spellings, whichever this is running on: one repository is\n * read on a Windows checkout and in Linux CI, so a path is absolute where it\n * was written rather than where it is being read. `C:docs` counts, because it\n * is relative to a drive rather than to a root, and prefixing it with a root\n * produces a third place that is neither.\n */\nexport function isAbsolutePath(value: string): boolean {\n return ABSOLUTE.test(value);\n}\n\n// A drive letter in lower case, at the start of a path or after the prefix\n// of a device path, `\\\\?\\` or `\\\\.\\`, as Node's `path.resolve` writes either.\nconst LOWER_DRIVE = /^(\\\\\\\\[?.]\\\\)?([a-z]):/;\n\n/**\n * A resolved path with its drive letter in upper case, for telling two paths\n * apart.\n *\n * Windows reads a drive letter in either case as one volume (Microsoft's\n * *Naming Files, Paths, and Namespaces*, *Naming Conventions*), and\n * `path.resolve` keeps the case it was typed in, so `C:\\x` beside `c:\\x` were\n * two values. Only the letter is folded: whether two names past it are one\n * directory is the disk's to say. A path Node resolves on any other host\n * starts with `/`, so nothing there is changed.\n */\nexport function foldDriveLetter(resolved: string): string {\n return resolved.replace(LOWER_DRIVE, (_drive, device: string | undefined, letter: string) => `${device ?? ''}${letter.toUpperCase()}:`);\n}\n\n/** Removes `.` and `..` segments. Leading `..` are preserved. */\nexport function normalisePosix(value: string): string {\n const absolute = value.startsWith('/');\n const out: string[] = [];\n for (const segment of value.split('/')) {\n if (segment === '' || segment === '.') continue;\n if (segment === '..') {\n const last = out[out.length - 1];\n if (out.length > 0 && last !== '..') out.pop();\n else if (!absolute) out.push('..');\n continue;\n }\n out.push(segment);\n }\n const joined = out.join('/');\n return absolute ? `/${joined}` : joined;\n}\n\n/** The directory containing `value`, or `''` at the root. */\nexport function dirnamePosix(value: string): string {\n const slash = value.lastIndexOf('/');\n return slash === -1 ? '' : value.slice(0, slash);\n}\n\n/** The final segment of `value`. */\nexport function basenamePosix(value: string): string {\n return value.slice(value.lastIndexOf('/') + 1);\n}\n\n/** Joins segments and normalises the result. */\nexport function joinPosix(...segments: readonly string[]): string {\n return normalisePosix(segments.filter((segment) => segment.length > 0).join('/'));\n}\n\n/** Resolves `target` against the directory holding `from`. */\nexport function resolveFrom(from: string, target: string): string {\n if (target.startsWith('/')) return normalisePosix(target);\n return joinPosix(dirnamePosix(from), target);\n}\n\n/** The extension including the dot, lower-cased, or `''`. */\nexport function extnamePosix(value: string): string {\n const base = basenamePosix(value);\n const dot = base.lastIndexOf('.');\n return dot <= 0 ? '' : base.slice(dot).toLowerCase();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * POSIX path arithmetic, independent of the host platform.\n *\n * Every path inside spec-graph is a repository-relative POSIX path, on Windows\n * as much as on Linux. Node's `path` module would happily produce\n * `docs\\adr\\0007.md` on one machine and `docs/adr/0007.md` on another, and a\n * graph whose node identities depend on which laptop built it is not a graph.\n */\n\n/** Converts a host path to POSIX form. */\nexport function toPosix(value: string): string {\n return value.replace(/\\\\/g, '/');\n}\n\nconst ABSOLUTE = /^(?:[/\\\\]|[A-Za-z]:)/;\n\n/**\n * Whether a path names a place outright rather than a place relative to one.\n *\n * Both platforms' spellings, whichever this is running on: one repository is\n * read on a Windows checkout and in Linux CI, so a path is absolute where it\n * was written rather than where it is being read. `C:docs` counts, because it\n * is relative to a drive rather than to a root, and prefixing it with a root\n * produces a third place that is neither.\n */\nexport function isAbsolutePath(value: string): boolean {\n return ABSOLUTE.test(value);\n}\n\n// A drive letter in lower case, at the start of a path or after the prefix\n// of a device path, `\\\\?\\` or `\\\\.\\`, as Node's `path.resolve` writes either.\nconst LOWER_DRIVE = /^(\\\\\\\\[?.]\\\\)?([a-z]):/;\n\n/**\n * A resolved path with its drive letter in upper case, for telling two paths\n * apart.\n *\n * Windows reads a drive letter in either case as one volume (Microsoft's\n * *Naming Files, Paths, and Namespaces*, *Naming Conventions*), and\n * `path.resolve` keeps the case it was typed in, so `C:\\x` beside `c:\\x` were\n * two values. Only the letter is folded: whether two names past it are one\n * directory is the disk's to say. A path Node resolves on any other host\n * starts with `/`, so nothing there is changed.\n */\nexport function foldDriveLetter(resolved: string): string {\n return resolved.replace(LOWER_DRIVE, (_drive, device: string | undefined, letter: string) => `${device ?? ''}${letter.toUpperCase()}:`);\n}\n\n/**\n * Whether a path the host resolved holds a `\\` inside a name, on a host whose\n * separator is `separator`.\n *\n * A root is read with each `\\` a separator, as Windows writes one, so a root\n * typed `docs\\adr` is `docs/adr` on every host. Where the host's separator is\n * `/`, a `\\` it resolved, from the directory a run starts in, is a character\n * of a name, and read as a separator it spells another directory: the walk,\n * the configuration and a recorded baseline went there (ADR-0010,\n * 2026-10-24). Where the separator is `\\`, no name can hold one.\n */\nexport function holdsBackslashInName(resolved: string, separator: string): boolean {\n return separator === '/' && resolved.includes('\\\\');\n}\n\n/** Removes `.` and `..` segments. Leading `..` are preserved. */\nexport function normalisePosix(value: string): string {\n const absolute = value.startsWith('/');\n const out: string[] = [];\n for (const segment of value.split('/')) {\n if (segment === '' || segment === '.') continue;\n if (segment === '..') {\n const last = out[out.length - 1];\n if (out.length > 0 && last !== '..') out.pop();\n else if (!absolute) out.push('..');\n continue;\n }\n out.push(segment);\n }\n const joined = out.join('/');\n return absolute ? `/${joined}` : joined;\n}\n\n/** The directory containing `value`, or `''` at the root. */\nexport function dirnamePosix(value: string): string {\n const slash = value.lastIndexOf('/');\n return slash === -1 ? '' : value.slice(0, slash);\n}\n\n/** The final segment of `value`. */\nexport function basenamePosix(value: string): string {\n return value.slice(value.lastIndexOf('/') + 1);\n}\n\n/** Joins segments and normalises the result. */\nexport function joinPosix(...segments: readonly string[]): string {\n return normalisePosix(segments.filter((segment) => segment.length > 0).join('/'));\n}\n\n/** Resolves `target` against the directory holding `from`. */\nexport function resolveFrom(from: string, target: string): string {\n if (target.startsWith('/')) return normalisePosix(target);\n return joinPosix(dirnamePosix(from), target);\n}\n\n/** The extension including the dot, lower-cased, or `''`. */\nexport function extnamePosix(value: string): string {\n const base = basenamePosix(value);\n const dot = base.lastIndexOf('.');\n return dot <= 0 ? '' : base.slice(dot).toLowerCase();\n}\n"]}
|
package/package.json
CHANGED