@myagentroam/node 0.9.97 → 0.9.98
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/ctags-binary.js +10 -0
- package/dist/service/code-navigation/c-family-path-specifier-resolver.js +40 -0
- package/dist/service/code-navigation/csharp-path-specifier-resolver.js +32 -0
- package/dist/service/code-navigation/ctags-index-storage.js +290 -0
- package/dist/service/code-navigation/ctags-query.js +140 -0
- package/dist/service/code-navigation/ecmascript-path-specifier-resolver.js +85 -0
- package/dist/service/code-navigation/file-reference-parser.js +28 -0
- package/dist/service/code-navigation/go-path-specifier-resolver.js +31 -0
- package/dist/service/code-navigation/jvm-path-specifier-resolver.js +28 -0
- package/dist/service/code-navigation/markdown-path-specifier-resolver.js +80 -0
- package/dist/service/code-navigation/navigation-resolution-definition.js +1 -0
- package/dist/service/code-navigation/navigation-resolution-registry.js +36 -0
- package/dist/service/code-navigation/navigation-target-validator.js +121 -0
- package/dist/service/code-navigation/path-specifier-resolver.js +6 -0
- package/dist/service/code-navigation/python-path-specifier-resolver.js +41 -0
- package/dist/service/code-navigation/rust-path-specifier-resolver.js +31 -0
- package/dist/service/code-navigation/stylesheet-path-specifier-resolver.js +55 -0
- package/dist/service/workspace-code-navigation-service.js +80 -694
- package/package.json +4 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { matchesPathSuffix } from './path-specifier-resolver.js';
|
|
2
|
+
function accepts(value) {
|
|
3
|
+
return /^[\p{L}_$][\p{L}\p{N}_$]*(?:\.[\p{L}_$][\p{L}\p{N}_$]*)+$/u.test(value);
|
|
4
|
+
}
|
|
5
|
+
function matches(path, _currentPath, specifier) {
|
|
6
|
+
return candidates(specifier).some((candidate) => matchesPathSuffix(path, candidate));
|
|
7
|
+
}
|
|
8
|
+
function score(path, _currentPath, specifier) {
|
|
9
|
+
const exact = candidates(specifier).findIndex((candidate) => matchesPathSuffix(path, candidate));
|
|
10
|
+
return exact < 0 ? Number.MAX_SAFE_INTEGER : exact * 10_000 + path.length;
|
|
11
|
+
}
|
|
12
|
+
function candidates(specifier) {
|
|
13
|
+
const segments = specifier.split('.');
|
|
14
|
+
return segments.flatMap((_, index) => {
|
|
15
|
+
const value = segments.slice(0, segments.length - index).join('/');
|
|
16
|
+
return ['.java', '.kt', '.kts'].map((suffix) => `${value}${suffix}`);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export const jvmPathSpecifierResolver = {
|
|
20
|
+
id: 'jvm.path-specifier',
|
|
21
|
+
accepts,
|
|
22
|
+
matches,
|
|
23
|
+
score
|
|
24
|
+
};
|
|
25
|
+
export const jvmNavigationResolutionDefinition = {
|
|
26
|
+
languageId: 'jvm',
|
|
27
|
+
resolver: jvmPathSpecifierResolver
|
|
28
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { posix } from 'node:path';
|
|
2
|
+
function accepts(value) {
|
|
3
|
+
return value === '.' || /^(?:\.\.?\/)?[A-Za-z0-9_./$+ -]+$/u.test(value);
|
|
4
|
+
}
|
|
5
|
+
function matches(path, currentPath, specifier) {
|
|
6
|
+
return candidates(currentPath, specifier).includes(path);
|
|
7
|
+
}
|
|
8
|
+
function score(path, currentPath, specifier) {
|
|
9
|
+
const index = candidates(currentPath, specifier).indexOf(path);
|
|
10
|
+
return index >= 0 ? index : Number.MAX_SAFE_INTEGER;
|
|
11
|
+
}
|
|
12
|
+
function candidates(currentPath, specifier) {
|
|
13
|
+
if (specifier === '.')
|
|
14
|
+
return [currentPath];
|
|
15
|
+
const resolved = posix.normalize(posix.join(posix.dirname(currentPath), specifier));
|
|
16
|
+
if (resolved === '..' || resolved.startsWith('../'))
|
|
17
|
+
return [];
|
|
18
|
+
const path = resolved.replace(/^\.\//u, '');
|
|
19
|
+
return path.includes('.')
|
|
20
|
+
? [path]
|
|
21
|
+
: [path, `${path}.md`, `${path}.markdown`, `${path}/README.md`, `${path}/readme.md`];
|
|
22
|
+
}
|
|
23
|
+
export function markdownAnchorLine(source, anchor) {
|
|
24
|
+
const requested = markdownAnchorSlug(anchor);
|
|
25
|
+
if (requested === '')
|
|
26
|
+
return undefined;
|
|
27
|
+
const counts = new Map();
|
|
28
|
+
const lines = source.split(/\r?\n/u);
|
|
29
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
30
|
+
const heading = markdownHeading(lines, index);
|
|
31
|
+
if (heading === undefined)
|
|
32
|
+
continue;
|
|
33
|
+
const base = markdownAnchorSlug(heading.text);
|
|
34
|
+
if (base === '')
|
|
35
|
+
continue;
|
|
36
|
+
const count = counts.get(base) ?? 0;
|
|
37
|
+
counts.set(base, count + 1);
|
|
38
|
+
const slug = count === 0 ? base : `${base}-${count}`;
|
|
39
|
+
if (slug === requested)
|
|
40
|
+
return heading.line;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
function markdownHeading(lines, index) {
|
|
45
|
+
const atx = /^[ \t]{0,3}#{1,6}[ \t]+(.+?)[ \t]*#*[ \t]*$/u.exec(lines[index] ?? '');
|
|
46
|
+
if (atx !== null)
|
|
47
|
+
return { text: atx[1], line: index + 1 };
|
|
48
|
+
const underline = /^[ \t]{0,3}(?:=+|-+)[ \t]*$/u.test(lines[index + 1] ?? '');
|
|
49
|
+
return underline && (lines[index] ?? '').trim().length > 0
|
|
50
|
+
? { text: lines[index], line: index + 1 }
|
|
51
|
+
: undefined;
|
|
52
|
+
}
|
|
53
|
+
function markdownAnchorSlug(value) {
|
|
54
|
+
return decodeURIComponentSafe(value)
|
|
55
|
+
.trim()
|
|
56
|
+
.toLowerCase()
|
|
57
|
+
.replace(/[`*_~[\]()]/gu, '')
|
|
58
|
+
.replace(/[^\p{L}\p{N}_ -]/gu, '')
|
|
59
|
+
.replace(/[\s-]+/gu, '-');
|
|
60
|
+
}
|
|
61
|
+
function decodeURIComponentSafe(value) {
|
|
62
|
+
try {
|
|
63
|
+
return decodeURIComponent(value);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export const markdownPathSpecifierResolver = {
|
|
70
|
+
id: 'markdown.path-specifier',
|
|
71
|
+
accepts,
|
|
72
|
+
directCandidates: candidates,
|
|
73
|
+
matches,
|
|
74
|
+
score,
|
|
75
|
+
anchorLine: markdownAnchorLine
|
|
76
|
+
};
|
|
77
|
+
export const markdownNavigationResolutionDefinition = {
|
|
78
|
+
languageId: 'markdown',
|
|
79
|
+
resolver: markdownPathSpecifierResolver
|
|
80
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { cFamilyNavigationResolutionDefinition, cNavigationResolutionDefinition, cppNavigationResolutionDefinition, objectiveCNavigationResolutionDefinition, objectiveCppNavigationResolutionDefinition } from './c-family-path-specifier-resolver.js';
|
|
2
|
+
import { csharpNavigationResolutionDefinition } from './csharp-path-specifier-resolver.js';
|
|
3
|
+
import { ecmascriptNavigationResolutionDefinition } from './ecmascript-path-specifier-resolver.js';
|
|
4
|
+
import { goNavigationResolutionDefinition } from './go-path-specifier-resolver.js';
|
|
5
|
+
import { jvmNavigationResolutionDefinition } from './jvm-path-specifier-resolver.js';
|
|
6
|
+
import { markdownNavigationResolutionDefinition } from './markdown-path-specifier-resolver.js';
|
|
7
|
+
import { pythonNavigationResolutionDefinition } from './python-path-specifier-resolver.js';
|
|
8
|
+
import { rustNavigationResolutionDefinition } from './rust-path-specifier-resolver.js';
|
|
9
|
+
import { cssNavigationResolutionDefinition, htmlNavigationResolutionDefinition, lessNavigationResolutionDefinition, sassNavigationResolutionDefinition, scssNavigationResolutionDefinition, vueNavigationResolutionDefinition } from './stylesheet-path-specifier-resolver.js';
|
|
10
|
+
const definitionsByLanguage = {
|
|
11
|
+
css: cssNavigationResolutionDefinition,
|
|
12
|
+
ecmascript: ecmascriptNavigationResolutionDefinition,
|
|
13
|
+
go: goNavigationResolutionDefinition,
|
|
14
|
+
html: htmlNavigationResolutionDefinition,
|
|
15
|
+
jvm: jvmNavigationResolutionDefinition,
|
|
16
|
+
csharp: csharpNavigationResolutionDefinition,
|
|
17
|
+
less: lessNavigationResolutionDefinition,
|
|
18
|
+
markdown: markdownNavigationResolutionDefinition,
|
|
19
|
+
python: pythonNavigationResolutionDefinition,
|
|
20
|
+
sass: sassNavigationResolutionDefinition,
|
|
21
|
+
scss: scssNavigationResolutionDefinition,
|
|
22
|
+
c: cNavigationResolutionDefinition,
|
|
23
|
+
cpp: cppNavigationResolutionDefinition,
|
|
24
|
+
'objective-c': objectiveCNavigationResolutionDefinition,
|
|
25
|
+
'objective-cpp': objectiveCppNavigationResolutionDefinition,
|
|
26
|
+
'c-family': cFamilyNavigationResolutionDefinition,
|
|
27
|
+
rust: rustNavigationResolutionDefinition,
|
|
28
|
+
vue: vueNavigationResolutionDefinition
|
|
29
|
+
};
|
|
30
|
+
export function navigationResolutionDefinitions() {
|
|
31
|
+
return Object.values(definitionsByLanguage);
|
|
32
|
+
}
|
|
33
|
+
export function pathSpecifierResolver(languageId, specifier) {
|
|
34
|
+
const definition = definitionsByLanguage[languageId];
|
|
35
|
+
return definition?.resolver.accepts(specifier) === true ? definition.resolver : undefined;
|
|
36
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { lstat, open, readFile, realpath } from 'node:fs/promises';
|
|
2
|
+
import { relative, resolve, sep } from 'node:path';
|
|
3
|
+
const MAX_SOURCE_BYTES = 4 * 1024 * 1024;
|
|
4
|
+
const READ_BLOCK_BYTES = 4096;
|
|
5
|
+
const MAX_TARGET_PREVIEW_CHARACTERS = 512;
|
|
6
|
+
export function sourceFileFingerprint(size, modifiedAt) {
|
|
7
|
+
return `${size}:${modifiedAt ?? -1}`;
|
|
8
|
+
}
|
|
9
|
+
export async function validateSymbolTarget(root, target, symbol, expectedFingerprint) {
|
|
10
|
+
const actual = await validatedFile(root, target.path, expectedFingerprint);
|
|
11
|
+
if (actual === undefined)
|
|
12
|
+
return undefined;
|
|
13
|
+
const line = await lineAt(actual, target.line);
|
|
14
|
+
return line !== undefined && containsSymbol(line, symbol) ? targetPreview(line) : undefined;
|
|
15
|
+
}
|
|
16
|
+
export async function validatePathTarget(root, path, expectedFingerprint, anchor, anchorLine) {
|
|
17
|
+
const actual = await validatedFile(root, path, expectedFingerprint);
|
|
18
|
+
if (actual === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
const line = anchor === undefined || anchorLine === undefined
|
|
21
|
+
? 1
|
|
22
|
+
: anchorLine(await readFile(actual, 'utf8').catch(() => ''), anchor);
|
|
23
|
+
if (line === undefined)
|
|
24
|
+
return undefined;
|
|
25
|
+
const preview = await lineAt(actual, line);
|
|
26
|
+
return preview === undefined ? undefined : { line, preview };
|
|
27
|
+
}
|
|
28
|
+
async function validatedFile(root, path, expectedFingerprint) {
|
|
29
|
+
const requested = resolve(root, ...path.split('/'));
|
|
30
|
+
const requestedMetadata = await lstat(requested).catch(() => undefined);
|
|
31
|
+
if (requestedMetadata === undefined ||
|
|
32
|
+
!requestedMetadata.isFile() ||
|
|
33
|
+
requestedMetadata.isSymbolicLink() ||
|
|
34
|
+
requestedMetadata.size > MAX_SOURCE_BYTES)
|
|
35
|
+
return undefined;
|
|
36
|
+
const actual = await realpath(requested).catch(() => undefined);
|
|
37
|
+
if (actual === undefined ||
|
|
38
|
+
relative(root, actual)
|
|
39
|
+
.split(sep)
|
|
40
|
+
.some((part) => part === '..'))
|
|
41
|
+
return undefined;
|
|
42
|
+
const metadata = await lstat(actual).catch(() => undefined);
|
|
43
|
+
if (metadata === undefined ||
|
|
44
|
+
!metadata.isFile() ||
|
|
45
|
+
metadata.isSymbolicLink() ||
|
|
46
|
+
metadata.size > MAX_SOURCE_BYTES ||
|
|
47
|
+
(expectedFingerprint !== undefined &&
|
|
48
|
+
sourceFileFingerprint(metadata.size, metadata.mtimeMs) !== expectedFingerprint))
|
|
49
|
+
return undefined;
|
|
50
|
+
return actual;
|
|
51
|
+
}
|
|
52
|
+
export function targetPreview(line) {
|
|
53
|
+
if (line.length <= MAX_TARGET_PREVIEW_CHARACTERS)
|
|
54
|
+
return line;
|
|
55
|
+
const contentLimit = MAX_TARGET_PREVIEW_CHARACTERS - 1;
|
|
56
|
+
const end = line.charCodeAt(contentLimit - 1);
|
|
57
|
+
const safeEnd = end >= 0xd800 && end <= 0xdbff ? contentLimit - 1 : contentLimit;
|
|
58
|
+
return `${line.slice(0, safeEnd)}…`;
|
|
59
|
+
}
|
|
60
|
+
async function lineAt(path, targetLine) {
|
|
61
|
+
const handle = await open(path, 'r');
|
|
62
|
+
try {
|
|
63
|
+
let offset = 0;
|
|
64
|
+
let line = 1;
|
|
65
|
+
let pending = Buffer.alloc(0);
|
|
66
|
+
while (offset < MAX_SOURCE_BYTES) {
|
|
67
|
+
const chunk = Buffer.alloc(READ_BLOCK_BYTES);
|
|
68
|
+
const { bytesRead } = await handle.read(chunk, 0, chunk.length, offset);
|
|
69
|
+
if (bytesRead === 0)
|
|
70
|
+
return line === targetLine ? pending.toString('utf8') : undefined;
|
|
71
|
+
offset += bytesRead;
|
|
72
|
+
let content = pending.length === 0
|
|
73
|
+
? chunk.subarray(0, bytesRead)
|
|
74
|
+
: Buffer.concat([pending, chunk.subarray(0, bytesRead)]);
|
|
75
|
+
let newline;
|
|
76
|
+
while ((newline = content.indexOf(0x0a)) >= 0) {
|
|
77
|
+
if (line === targetLine)
|
|
78
|
+
return content.subarray(0, newline).toString('utf8');
|
|
79
|
+
line += 1;
|
|
80
|
+
content = content.subarray(newline + 1);
|
|
81
|
+
}
|
|
82
|
+
pending = content;
|
|
83
|
+
}
|
|
84
|
+
return line === targetLine ? pending.toString('utf8') : undefined;
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
await handle.close();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export function containsSymbol(line, symbol) {
|
|
91
|
+
const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
92
|
+
const optionalScssPrefix = symbol.startsWith('$') ? '' : '\\$?';
|
|
93
|
+
return new RegExp(`(?:^|[^\\p{L}\\p{N}_$])${optionalScssPrefix}${escaped}(?![\\p{L}\\p{N}_$])`, 'u').test(line);
|
|
94
|
+
}
|
|
95
|
+
export function compareTargets(left, right, currentPath) {
|
|
96
|
+
const leftScore = targetScore(left, currentPath);
|
|
97
|
+
const rightScore = targetScore(right, currentPath);
|
|
98
|
+
return (rightScore - leftScore ||
|
|
99
|
+
left.path.localeCompare(right.path) ||
|
|
100
|
+
left.line - right.line ||
|
|
101
|
+
(left.kind ?? '').localeCompare(right.kind ?? ''));
|
|
102
|
+
}
|
|
103
|
+
function targetScore(target, currentPath) {
|
|
104
|
+
if (target.path === currentPath)
|
|
105
|
+
return 100;
|
|
106
|
+
const currentDirectory = currentPath.includes('/')
|
|
107
|
+
? currentPath.slice(0, currentPath.lastIndexOf('/'))
|
|
108
|
+
: '';
|
|
109
|
+
const targetDirectory = target.path.includes('/')
|
|
110
|
+
? target.path.slice(0, target.path.lastIndexOf('/'))
|
|
111
|
+
: '';
|
|
112
|
+
return commonPathSegments(currentDirectory, targetDirectory);
|
|
113
|
+
}
|
|
114
|
+
function commonPathSegments(left, right) {
|
|
115
|
+
const leftParts = left === '' ? [] : left.split('/');
|
|
116
|
+
const rightParts = right === '' ? [] : right.split('/');
|
|
117
|
+
let count = 0;
|
|
118
|
+
while (count < leftParts.length && leftParts[count] === rightParts[count])
|
|
119
|
+
count += 1;
|
|
120
|
+
return count;
|
|
121
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { matchesPathSuffix, shortestPathScore } from './path-specifier-resolver.js';
|
|
2
|
+
import { posix } from 'node:path';
|
|
3
|
+
function accepts(value) {
|
|
4
|
+
return (/^[\p{L}_$][\p{L}\p{N}_$]*(?:\.[\p{L}_$][\p{L}\p{N}_$]*)*$/u.test(value) ||
|
|
5
|
+
/^\.+(?:[\p{L}_$][\p{L}\p{N}_$]*(?:\.[\p{L}_$][\p{L}\p{N}_$]*)*)?$/u.test(value));
|
|
6
|
+
}
|
|
7
|
+
function matches(path, currentPath, specifier) {
|
|
8
|
+
return candidates(currentPath, specifier).some((candidate) => matchesPathSuffix(path, candidate));
|
|
9
|
+
}
|
|
10
|
+
function directCandidates(currentPath, specifier) {
|
|
11
|
+
return specifier.startsWith('.') ? candidates(currentPath, specifier) : [];
|
|
12
|
+
}
|
|
13
|
+
function candidates(currentPath, specifier) {
|
|
14
|
+
const packagePath = relativePackagePath(currentPath, specifier);
|
|
15
|
+
if (packagePath === undefined)
|
|
16
|
+
return [];
|
|
17
|
+
return packagePath === '.'
|
|
18
|
+
? ['__init__.py']
|
|
19
|
+
: [`${packagePath}.py`, `${packagePath}.pyw`, `${packagePath}/__init__.py`];
|
|
20
|
+
}
|
|
21
|
+
function relativePackagePath(currentPath, specifier) {
|
|
22
|
+
if (!specifier.startsWith('.'))
|
|
23
|
+
return specifier.replaceAll('.', '/');
|
|
24
|
+
const levels = specifier.match(/^\.+/u)?.[0].length ?? 0;
|
|
25
|
+
const module = specifier.slice(levels).replaceAll('.', '/');
|
|
26
|
+
const base = posix.normalize(posix.join(posix.dirname(currentPath), ...Array.from({ length: levels - 1 }, () => '..')));
|
|
27
|
+
if (base === '..' || base.startsWith('../'))
|
|
28
|
+
return undefined;
|
|
29
|
+
return module.length === 0 ? base : posix.join(base, module);
|
|
30
|
+
}
|
|
31
|
+
export const pythonPathSpecifierResolver = {
|
|
32
|
+
id: 'python.path-specifier',
|
|
33
|
+
accepts,
|
|
34
|
+
directCandidates,
|
|
35
|
+
matches,
|
|
36
|
+
score: shortestPathScore
|
|
37
|
+
};
|
|
38
|
+
export const pythonNavigationResolutionDefinition = {
|
|
39
|
+
languageId: 'python',
|
|
40
|
+
resolver: pythonPathSpecifierResolver
|
|
41
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { posix } from 'node:path';
|
|
2
|
+
function accepts(value) {
|
|
3
|
+
return (/^[A-Za-z_][A-Za-z0-9_]*$/u.test(value) || /^(?:\.\.?\/)?[A-Za-z0-9_./-]+\.rs$/u.test(value));
|
|
4
|
+
}
|
|
5
|
+
function matches(path, currentPath, specifier) {
|
|
6
|
+
return candidates(currentPath, specifier).includes(path);
|
|
7
|
+
}
|
|
8
|
+
function score(path, currentPath, specifier) {
|
|
9
|
+
const index = candidates(currentPath, specifier).indexOf(path);
|
|
10
|
+
return index >= 0 ? index : Number.MAX_SAFE_INTEGER;
|
|
11
|
+
}
|
|
12
|
+
function candidates(currentPath, specifier) {
|
|
13
|
+
const directory = posix.dirname(currentPath);
|
|
14
|
+
if (specifier.endsWith('.rs')) {
|
|
15
|
+
const resolved = posix.normalize(posix.join(directory, specifier));
|
|
16
|
+
return resolved.startsWith('../') || resolved === '..' ? [] : [resolved];
|
|
17
|
+
}
|
|
18
|
+
const base = directory === '.' ? specifier : `${directory}/${specifier}`;
|
|
19
|
+
return [`${base}.rs`, `${base}/mod.rs`];
|
|
20
|
+
}
|
|
21
|
+
export const rustPathSpecifierResolver = {
|
|
22
|
+
id: 'rust.path-specifier',
|
|
23
|
+
accepts,
|
|
24
|
+
directCandidates: candidates,
|
|
25
|
+
matches,
|
|
26
|
+
score
|
|
27
|
+
};
|
|
28
|
+
export const rustNavigationResolutionDefinition = {
|
|
29
|
+
languageId: 'rust',
|
|
30
|
+
resolver: rustPathSpecifierResolver
|
|
31
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { posix } from 'node:path';
|
|
2
|
+
function accepts(value) {
|
|
3
|
+
return /^(?:\.\.?\/)?[A-Za-z0-9_./$+@ -]+$/u.test(value);
|
|
4
|
+
}
|
|
5
|
+
function createResolver(languageId, extensions, partials = false) {
|
|
6
|
+
const candidates = (currentPath, specifier) => pathCandidates(currentPath, specifier, extensions, partials);
|
|
7
|
+
return {
|
|
8
|
+
id: `${languageId}.path-specifier`,
|
|
9
|
+
accepts,
|
|
10
|
+
directCandidates: candidates,
|
|
11
|
+
matches: (path, currentPath, specifier) => candidates(currentPath, specifier).includes(path),
|
|
12
|
+
score: (path, currentPath, specifier) => {
|
|
13
|
+
const index = candidates(currentPath, specifier).indexOf(path);
|
|
14
|
+
return index >= 0 ? index : Number.MAX_SAFE_INTEGER;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function pathCandidates(currentPath, specifier, extensions, partials) {
|
|
19
|
+
const resolved = posix.normalize(posix.join(posix.dirname(currentPath), specifier));
|
|
20
|
+
if (resolved === '..' || resolved.startsWith('../'))
|
|
21
|
+
return [];
|
|
22
|
+
const path = resolved.replace(/^\.\//u, '');
|
|
23
|
+
if (path.slice(path.lastIndexOf('/') + 1).includes('.'))
|
|
24
|
+
return [path];
|
|
25
|
+
const base = extensions.flatMap((extension) => [
|
|
26
|
+
`${path}${extension}`,
|
|
27
|
+
`${path}/index${extension}`
|
|
28
|
+
]);
|
|
29
|
+
if (!partials)
|
|
30
|
+
return base;
|
|
31
|
+
const directory = posix.dirname(path);
|
|
32
|
+
const name = path.slice(path.lastIndexOf('/') + 1);
|
|
33
|
+
return [...base, ...extensions.map((extension) => posix.join(directory, `_${name}${extension}`))];
|
|
34
|
+
}
|
|
35
|
+
function definition(languageId, extensions, partials = false) {
|
|
36
|
+
return { languageId, resolver: createResolver(languageId, extensions, partials) };
|
|
37
|
+
}
|
|
38
|
+
export const cssNavigationResolutionDefinition = definition('css', ['.css']);
|
|
39
|
+
export const scssNavigationResolutionDefinition = definition('scss', ['.scss', '.css'], true);
|
|
40
|
+
export const sassNavigationResolutionDefinition = definition('sass', ['.sass', '.scss', '.css'], true);
|
|
41
|
+
export const lessNavigationResolutionDefinition = definition('less', ['.less', '.css']);
|
|
42
|
+
export const htmlNavigationResolutionDefinition = definition('html', [
|
|
43
|
+
'.html',
|
|
44
|
+
'.htm',
|
|
45
|
+
'.css',
|
|
46
|
+
'.js'
|
|
47
|
+
]);
|
|
48
|
+
export const vueNavigationResolutionDefinition = definition('vue', [
|
|
49
|
+
'.vue',
|
|
50
|
+
'.html',
|
|
51
|
+
'.css',
|
|
52
|
+
'.scss',
|
|
53
|
+
'.sass',
|
|
54
|
+
'.less'
|
|
55
|
+
]);
|