@plaited/development-skills 0.4.0 → 0.4.1
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/LICENSE +1 -1
- package/README.md +5 -0
- package/package.json +1 -1
- package/src/resolve-file-path.ts +29 -5
- package/src/tests/resolve-file-path.spec.ts +45 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# development-skills
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@plaited/development-skills)
|
|
4
|
+
[](https://github.com/plaited/development-skills/actions/workflows/ci.yml)
|
|
5
|
+
[](https://opensource.org/licenses/ISC)
|
|
6
|
+
|
|
7
|
+
|
|
3
8
|
TypeScript LSP, code documentation, and validation tools. Available as both a CLI tool and as installable skills for AI coding agents.
|
|
4
9
|
|
|
5
10
|
## CLI Tool
|
package/package.json
CHANGED
package/src/resolve-file-path.ts
CHANGED
|
@@ -1,28 +1,52 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check if a path looks like a file path (vs a package specifier)
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* File paths typically contain a `/` and end with a file extension.
|
|
8
|
+
* Package specifiers are bare like `lodash` or scoped like `@org/pkg`.
|
|
9
|
+
* Scoped packages starting with `@` are excluded even if they have extensions.
|
|
10
|
+
*/
|
|
11
|
+
const looksLikeFilePath = (path: string): boolean => {
|
|
12
|
+
// Scoped packages like @org/pkg/file.ts should use Bun.resolve()
|
|
13
|
+
if (path.startsWith('@')) return false
|
|
14
|
+
// Contains a slash and ends with a common source file extension
|
|
15
|
+
return path.includes('/') && /\.(tsx?|jsx?|mjs|cjs|json)$/.test(path)
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
/**
|
|
2
19
|
* Resolve a file path to an absolute path
|
|
3
20
|
*
|
|
4
21
|
* @remarks
|
|
5
22
|
* Handles three types of paths:
|
|
6
23
|
* - Absolute paths (starting with `/`) - returned as-is
|
|
7
|
-
* - Relative paths (starting with `.`) - resolved from cwd
|
|
24
|
+
* - Relative paths (starting with `.` or looking like `src/foo.ts`) - resolved from cwd
|
|
8
25
|
* - Package export paths (e.g., `plaited/workshop/get-paths.ts`) - resolved via Bun.resolve()
|
|
9
26
|
*/
|
|
10
27
|
export const resolveFilePath = async (filePath: string): Promise<string> => {
|
|
28
|
+
const cwd = process.cwd()
|
|
29
|
+
|
|
11
30
|
// Absolute path
|
|
12
31
|
if (filePath.startsWith('/')) {
|
|
13
32
|
return filePath
|
|
14
33
|
}
|
|
15
34
|
|
|
16
|
-
//
|
|
35
|
+
// Explicit relative path from cwd (starts with . or ..)
|
|
17
36
|
if (filePath.startsWith('.')) {
|
|
18
|
-
return
|
|
37
|
+
return join(cwd, filePath)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Implicit relative path (looks like a file path, e.g., src/utils/foo.ts)
|
|
41
|
+
if (looksLikeFilePath(filePath)) {
|
|
42
|
+
return join(cwd, filePath)
|
|
19
43
|
}
|
|
20
44
|
|
|
21
45
|
// Try package export path resolution
|
|
22
46
|
try {
|
|
23
|
-
return await Bun.resolve(filePath,
|
|
47
|
+
return await Bun.resolve(filePath, cwd)
|
|
24
48
|
} catch {
|
|
25
49
|
// Fall back to relative path from cwd
|
|
26
|
-
return
|
|
50
|
+
return join(cwd, filePath)
|
|
27
51
|
}
|
|
28
52
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { join } from 'node:path'
|
|
2
3
|
import { resolveFilePath } from '../resolve-file-path.ts'
|
|
3
4
|
|
|
4
5
|
describe('resolveFilePath', () => {
|
|
@@ -9,9 +10,10 @@ describe('resolveFilePath', () => {
|
|
|
9
10
|
})
|
|
10
11
|
|
|
11
12
|
test('resolves relative path from cwd', async () => {
|
|
12
|
-
const relativePath = './
|
|
13
|
+
const relativePath = './src/resolve-file-path.ts'
|
|
13
14
|
const result = await resolveFilePath(relativePath)
|
|
14
|
-
|
|
15
|
+
// join() normalizes paths, removing the ./
|
|
16
|
+
expect(result).toBe(join(process.cwd(), relativePath))
|
|
15
17
|
})
|
|
16
18
|
|
|
17
19
|
test('resolves package export path via Bun.resolve', async () => {
|
|
@@ -28,6 +30,46 @@ describe('resolveFilePath', () => {
|
|
|
28
30
|
const invalidPath = 'nonexistent-package/file.ts'
|
|
29
31
|
const result = await resolveFilePath(invalidPath)
|
|
30
32
|
|
|
31
|
-
expect(result).toBe(
|
|
33
|
+
expect(result).toBe(join(process.cwd(), invalidPath))
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('resolves implicit relative path (src/foo.ts format) from cwd', async () => {
|
|
37
|
+
// Paths that look like file paths (contain / and end with extension)
|
|
38
|
+
// should resolve from cwd without trying Bun.resolve()
|
|
39
|
+
const implicitRelative = 'src/utils/parser.ts'
|
|
40
|
+
const result = await resolveFilePath(implicitRelative)
|
|
41
|
+
|
|
42
|
+
expect(result).toBe(join(process.cwd(), implicitRelative))
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('resolves various file extensions as implicit relative paths', async () => {
|
|
46
|
+
const extensions = ['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'json']
|
|
47
|
+
|
|
48
|
+
for (const ext of extensions) {
|
|
49
|
+
const path = `src/file.${ext}`
|
|
50
|
+
const result = await resolveFilePath(path)
|
|
51
|
+
expect(result).toBe(join(process.cwd(), path))
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('treats bare package names without extensions as package specifiers', async () => {
|
|
56
|
+
// A path like 'typescript' (no slash, no extension) should try Bun.resolve()
|
|
57
|
+
const barePkg = 'typescript'
|
|
58
|
+
const result = await resolveFilePath(barePkg)
|
|
59
|
+
|
|
60
|
+
// Should resolve to node_modules, not cwd/typescript
|
|
61
|
+
expect(result).toContain('node_modules/typescript')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('treats scoped packages as package specifiers, not implicit file paths', async () => {
|
|
65
|
+
// Scoped packages like @org/pkg/file.ts should NOT be treated as implicit
|
|
66
|
+
// relative paths, even if they contain / and end with an extension.
|
|
67
|
+
// They should go through Bun.resolve() first, falling back to cwd if not found.
|
|
68
|
+
const scopedPkg = '@nonexistent/pkg/src/file.ts'
|
|
69
|
+
const result = await resolveFilePath(scopedPkg)
|
|
70
|
+
|
|
71
|
+
// Falls back to cwd since package doesn't exist, but importantly it tried
|
|
72
|
+
// Bun.resolve() first (doesn't match looksLikeFilePath due to @ prefix)
|
|
73
|
+
expect(result).toBe(join(process.cwd(), scopedPkg))
|
|
32
74
|
})
|
|
33
75
|
})
|