Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hip-peas-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'tsconfck': patch
---

fix types
10 changes: 5 additions & 5 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ export function find(filename: string, options?: TSConfckFindOptions): Promise<s
#### TSConfckFindOptions

```ts
export interface TSConfckFindOptions {
export interface TSConfckFindOptions<T = TSConfckParseResult | TSConfckParseNativeResult> {
/**
* A cache to improve performance for multiple calls in the same project
*
* Warning: You must clear this cache in case tsconfig files are added/removed during it's lifetime
*/
cache?: TSConfckCache<TSConfckParseResult | TSConfckParseNativeResult>;
cache?: TSConfckCache<T>;

/**
* project root dir, does not continue scanning outside of this directory.
Expand Down Expand Up @@ -67,7 +67,7 @@ export function parse(filename: string, options?: TSConfckParseOptions): Promise
#### TSConfckParseOptions

```ts
export interface TSConfckParseOptions extends TSConfckFindOptions {
export interface TSConfckParseOptions extends TSConfckFindOptions<TSConfckParseResult> {
// same as find options
}
```
Expand Down Expand Up @@ -116,7 +116,7 @@ export class TSConfckParseError extends Error {
* @param tsconfigFile - path to tsconfig file
* @param cause - cause of this error
*/
constructor(message: string, code: string, tsconfigFile: string, cause: Error | null);
constructor(message: string, code: string, tsconfigFile: string, cause?: Error);
/**
* error code
* */
Expand Down Expand Up @@ -164,7 +164,7 @@ export function parseNative(filename: string, options?: TSConfckParseNativeOptio
#### TSConfckParseNativeOptions

```ts
export interface TSConfckParseNativeOptions extends TSConfckParseOptions {
export interface TSConfckParseNativeOptions extends TSConfckFindOptions<TSConfckParseNativeResult> {
/**
* Set this option to true to force typescript to ignore all source files.
*
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@changesets/cli": "^2.29.7",
"@eslint/js": "^9.35.0",
"@svitejs/changesets-changelog-github-compact": "^1.2.0",
"@types/node": "^24.8.1",
"dts-buddy": "^0.6.2",
"esbuild": "^0.25.9",
"eslint": "^9.35.0",
Expand Down
5 changes: 4 additions & 1 deletion packages/tsconfck/bin/tsconfck.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ parse tsconfig for a file
const HELP_ARGS = ['-h', '--help', '-?', 'help'];
const JS_ARG = '-js';
const COMMANDS = ['find', 'find-all', 'find-all', 'parse', 'parse-result'];
/**
* @param {string[]} args
*/
function needsHelp(args) {
if (args.some((arg) => HELP_ARGS.includes(arg))) {
return HELP_TEXT;
Expand Down Expand Up @@ -65,7 +68,7 @@ async function main() {

main().then(
(result) => {
process.stdout.write(result);
process.stdout.write(result ?? '');
process.stdout.write('\n');
},
(err) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/tsconfck/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@
},
"scripts": {
"check:publint": "publint --strict",
"check:types": "tsc --noEmit",
"check:types": "tsc",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest",
"dts-buddy": "dts-buddy -m \"tsconfck:src/index.js\""
"dts-buddy": "dts-buddy -m tsconfck:src/public.d.ts"
}
}
10 changes: 5 additions & 5 deletions packages/tsconfck/src/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ export class TSConfckCache {
getConfigPath(dir, configName = 'tsconfig.json') {
const key = `${dir}/${configName}`;
const value = this.#configPaths.get(key);
// @ts-expect-error loosely check string or promise type
if (value == null || value.length || value.then) {
return value;
return value ?? null;
} else {
throw value;
}
Expand All @@ -52,7 +53,8 @@ export class TSConfckCache {
*/
getParseResult(file) {
const value = this.#parsed.get(file);
if (value.then || value.tsconfig) {
// @ts-expect-error loosely check promise or tsconfig type
if (value && (value.then || value.tsconfig)) {
return value;
} else {
throw value; // cached error, rethrow
Expand All @@ -62,7 +64,7 @@ export class TSConfckCache {
/**
* @internal
* @private
* @param file
* @param {string} file
* @param {boolean} isRootFile a flag to check if current file which involking the parse() api, used to distinguish the normal cache which only parsed by parseFile()
* @param {Promise<T>} result
*/
Expand Down Expand Up @@ -114,15 +116,13 @@ export class TSConfckCache {
/**
* map directories to their closest tsconfig.json
* @internal
* @private
* @type{Map<string,(Promise<string|null>|string|null)>}
*/
#configPaths = new Map();

/**
* map files to their parsed tsconfig result
* @internal
* @private
* @type {Map<string,(Promise<T>|T)> }
*/
#parsed = new Map();
Expand Down
9 changes: 4 additions & 5 deletions packages/tsconfck/src/find-all.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import path from 'node:path';
import { readdir } from 'node:fs';

/**
* @typedef WalkState
* @interface
* @typedef {Object} WalkState
* @property {string[]} files - files
* @property {number} calls - number of ongoing calls
* @property {(dir: string)=>boolean} skip - function to skip dirs
* @property {(dir: string)=>boolean} [skip] - function to skip dirs
* @property {boolean} err - error flag
* @property {string[]} configNames - config file names
*/
Expand Down Expand Up @@ -38,7 +37,7 @@ export async function findAll(dir, options) {
*
* @param {string} dir
* @param {WalkState} state
* @param {(err: NodeJS.ErrnoException | null, files?: string[]) => void} done
* @param {(err: NodeJS.ErrnoException | null, files: string[]) => void} done
*/
function walk(dir, state, done) {
if (state.err) {
Expand All @@ -52,7 +51,7 @@ function walk(dir, state, done) {
// skip deleted or inaccessible directories
if (err && !(err.code === 'ENOENT' || err.code === 'EACCES' || err.code === 'EPERM')) {
state.err = true;
done(err);
done(err, []);
} else {
for (const ent of entries) {
if (ent.isDirectory() && !state.skip?.(ent.name)) {
Expand Down
8 changes: 6 additions & 2 deletions packages/tsconfck/src/find-native.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import { isInNodeModules, loadTS, native2posix } from './util.js';
export async function findNative(filename, options) {
let dir = native2posix(path.dirname(path.resolve(filename)));
if (options?.ignoreNodeModules && isInNodeModules(dir)) {
// TODO: This returns a different type than the function signature says. Fix this in another PR.
// @ts-expect-error
return null;
}
const cache = options?.cache;
const root = options?.root ? native2posix(path.resolve(options.root)) : undefined;
const configName = options?.configName ?? 'tsconfig.json';
if (cache?.hasConfigPath(dir, configName)) {
// @ts-expect-error This never returns null
return cache.getConfigPath(dir, configName);
}
const ts = await loadTS();
Expand All @@ -36,7 +39,7 @@ export async function findNative(filename, options) {
/**
*
* @param {string} tsconfigFile
* @param {string} root
* @param {string} [root]
*/
function is_out_of_root(tsconfigFile, root) {
return root && !tsconfigFile.startsWith(root);
Expand All @@ -47,7 +50,7 @@ function is_out_of_root(tsconfigFile, root) {
* if no tsconfig was found, go up until root
* @param {string|null} tsconfigFile
* @param {string} fileDir
* @param {import('./cache.js').TSConfckCache} cache
* @param {import('./cache.js').TSConfckCache<import('./public.d.ts').TSConfckParseResult | import('./public.d.ts').TSConfckParseNativeResult>} cache
* @param {string|undefined} root
* @param {string} configName
*/
Expand All @@ -65,6 +68,7 @@ function cache_result(tsconfigFile, fileDir, cache, root, configName) {
}
}
directories.forEach((d) => {
// @ts-expect-error accessing private method because dts-buddy can't strip internal types for some reason
cache.setConfigPath(d, Promise.resolve(tsconfigFile), configName);
});
}
7 changes: 5 additions & 2 deletions packages/tsconfck/src/find.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,15 @@ function findUp(dir, { resolve, reject, promise }, options) {
reject(e);
return;
}

// @ts-expect-error loosely check promise
if (cached?.then) {
cached.then(resolve).catch(reject);
/** @type {Promise<string | null>} */ (cached).then(resolve).catch(reject);
} else {
resolve(cached);
resolve(/** @type {string | null} */ (cached));
}
} else {
// @ts-expect-error accessing private method because dts-buddy can't strip internal types for some reason
cache.setConfigPath(dir, promise, configName);
}
}
Expand Down
22 changes: 14 additions & 8 deletions packages/tsconfck/src/parse-native.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
} from './util.js';
import { findNative } from './find-native.js';

/** @typedef {import('./cache.js').TSConfckCache<import('./public.d.ts').TSConfckParseNativeResult>} ParseNativeCache */

const notFoundResult = {
tsconfigFile: null,
tsconfig: {},
Expand All @@ -27,7 +29,7 @@ const notFoundResult = {
* @throws {TSConfckParseNativeError}
*/
export async function parseNative(filename, options) {
/** @type {import('./cache.js').TSConfckCache} */
/** @type {ParseNativeCache | undefined} */
const cache = options?.cache;
if (cache?.hasParseResult(filename)) {
return cache.getParseResult(filename);
Expand All @@ -38,6 +40,7 @@ export async function parseNative(filename, options) {
/** @type {Promise<import('./public.d.ts').TSConfckParseNativeResult>}*/
promise
} = makePromise();
// @ts-expect-error accessing private method because dts-buddy can't strip internal types for some reason
cache?.setParseResult(filename, promise);
try {
const tsconfigFile =
Expand All @@ -54,6 +57,7 @@ export async function parseNative(filename, options) {
const ts = await loadTS();
result = await parseFile(tsconfigFile, ts, options, filename === tsconfigFile);
await parseReferences(result, ts, options);
// @ts-expect-error accessing private method because dts-buddy can't strip internal types for some reason
cache?.setParseResult(tsconfigFile, Promise.resolve(result));
}

Expand All @@ -71,12 +75,12 @@ export async function parseNative(filename, options) {
* @param {any} ts
* @param {import('./public.d.ts').TSConfckParseNativeOptions} [options]
* @param {boolean} [skipCache]
* @returns {import('./public.d.ts').TSConfckParseNativeResult}
* @returns {Promise<import('./public.d.ts').TSConfckParseNativeResult>}
*/
function parseFile(tsconfigFile, ts, options, skipCache) {
async function parseFile(tsconfigFile, ts, options, skipCache) {
const cache = options?.cache;
if (!skipCache && cache?.hasParseResult(tsconfigFile)) {
return cache.getParseResult(tsconfigFile);
return await cache.getParseResult(tsconfigFile);
}
const posixTSConfigFile = native2posix(tsconfigFile);
const { parseJsonConfigFileContent, readConfigFile, sys } = ts;
Expand Down Expand Up @@ -114,6 +118,7 @@ function parseFile(tsconfigFile, ts, options, skipCache) {
};

if (!skipCache) {
// @ts-expect-error accessing private method because dts-buddy can't strip internal types for some reason
cache?.setParseResult(tsconfigFile, Promise.resolve(result));
}

Expand Down Expand Up @@ -154,7 +159,8 @@ function checkErrors(nativeResult, tsconfigFile) {
18003 // no inputs
];
const criticalError = nativeResult.errors?.find(
(error) => error.category === 1 && !ignoredErrorCodes.includes(error.code)
(/** @type {TSDiagnosticError} */ error) =>
error.category === 1 && !ignoredErrorCodes.includes(error.code)
);
if (criticalError) {
throw new TSConfckParseNativeError(criticalError, tsconfigFile, nativeResult);
Expand Down Expand Up @@ -192,7 +198,7 @@ function result2tsconfig(result, ts, tsconfigFile) {
if (compilerOptions) {
if (compilerOptions.lib != null) {
// remove lib. and .dts from lib.es2019.d.ts etc
compilerOptions.lib = compilerOptions.lib.map((x) =>
compilerOptions.lib = compilerOptions.lib.map((/** @type {string} */ x) =>
x.replace(/^lib\./, '').replace(/\.d\.ts$/, '')
);
}
Expand Down Expand Up @@ -297,9 +303,9 @@ export class TSConfckParseNativeError extends Error {
result;
}

/** @typedef TSDiagnosticError {
/** @typedef {{
code: number;
category: number;
messageText: string;
start?: number;
} TSDiagnosticError */
}} TSDiagnosticError */
Loading