Socket
Socket
Sign inDemoInstall

tsconfck

Package Overview
Dependencies
1
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.0-next.3 to 3.0.0-next.4

7

bin/tsconfck.js

@@ -53,3 +53,8 @@ #!/usr/bin/env node

if (command === 'find') {
return find(file);
return find(file).then((found) => {
if (!found) {
throw new Error(`no tsconfig found for ${file}`);
}
return found;
});
} else if (command === 'parse') {

@@ -56,0 +61,0 @@ return JSON.stringify((await parse(file)).tsconfig, null, 2);

2

package.json
{
"name": "tsconfck",
"version": "3.0.0-next.3",
"version": "3.0.0-next.4",
"description": "A utility to work with tsconfig.json without typescript",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -0,21 +1,9 @@

/** @template T */
export class TSConfckCache {
/**
* clear cache, use this if you have a long running process and tsconfig files have been added,changed or deleted
* await it to ensure all find and parse calls are settled before continuing
*/
async clear() {
if (!this.#clearing) {
this.#clearing = Promise.allSettled([
...this.#tsconfigPaths.values(),
...this.#parsed.values()
])
.then(() => {
this.#tsconfigPaths.clear();
this.#parsed.clear();
})
.finally(() => {
this.#clearing = undefined;
});
}
return this.#clearing;
clear() {
this.#tsconfigPaths.clear();
this.#parsed.clear();
}

@@ -35,5 +23,5 @@

* @param {string} dir
* @returns {import('./public.d.ts').Awaitable<string|null>}
* @returns {Promise<string|null>|string|null}
*/
async getTSConfigPath(dir) {
getTSConfigPath(dir) {
return this.#tsconfigPaths.get(dir);

@@ -54,3 +42,3 @@ }

* @param {string} file
* @returns {import('./public.d.ts').Awaitable<import('./public.d.ts').TSConfckParseResult | import('./public.d.ts').TSConfckParseNativeResult>}
* @returns {Promise<T>|T}
*/

@@ -65,7 +53,17 @@ getParseResult(file) {

* @param file
* @param {Promise<import('./public.d.ts').TSConfckParseResult | import('./public.d.ts').TSConfckParseNativeResult>} result
* @param {Promise<T>|T} result
*/
setParseResult(file, result) {
this.#parsed.set(file, result);
result.then((parsed) => this.#parsed.set(file, parsed)).catch(() => this.#parsed.delete(file));
result
.then((parsed) => {
if (this.#parsed.get(file) === result) {
this.#parsed.set(file, parsed);
}
})
.catch(() => {
if (this.#parsed.get(file) === result) {
this.#parsed.delete(file);
}
});
}

@@ -76,13 +74,4 @@

* @private
* @param file
*/
deleteParseResult(file) {
this.#parsed.delete(file);
}
/**
* @internal
* @private
* @param {string} dir
* @param {Promise<string|null>} tsconfigPath
* @param {Promise<string|null>|string|null} tsconfigPath
*/

@@ -92,4 +81,12 @@ setTSConfigPath(dir, tsconfigPath) {

tsconfigPath
.then((path) => this.#tsconfigPaths.set(dir, path))
.catch(() => this.#tsconfigPaths.delete(dir));
.then((path) => {
if (this.#tsconfigPaths.get(dir) === tsconfigPath) {
this.#tsconfigPaths.set(dir, path);
}
})
.catch(() => {
if (this.#tsconfigPaths.get(dir) === tsconfigPath) {
this.#tsconfigPaths.delete(dir);
}
});
}

@@ -101,3 +98,3 @@

* @private
* @type{Map<string,import('./public.d.ts').Awaitable<string|null>>}
* @type{Map<string,(Promise<string|null>|string|null)>}
*/

@@ -110,8 +107,5 @@ #tsconfigPaths = new Map();

* @private
* @type {Map<string,import('./public.d.ts').Awaitable<import('./public.d.ts').TSConfckParseResult | import('./public.d.ts').TSConfckParseNativeResult>> }
* @type {Map<string,(Promise<T>|T)> }
*/
#parsed = new Map();
/** @type{Promise<void>} */
#clearing;
}
import path from 'path';
import { readdir } from 'fs';
import { readdir } from 'node:fs';

@@ -4,0 +4,0 @@ /**

@@ -1,4 +0,3 @@

import path from 'path';
import { promises as fs } from 'fs';
import path from 'node:path';
import fs from 'node:fs';
/**

@@ -9,3 +8,3 @@ * find the closest tsconfig.json file

* @param {import('./public.d.ts').TSConfckFindOptions} [options] - options
* @returns {Promise<string>} absolute path to closest tsconfig.json
* @returns {Promise<string|null>} absolute path to closest tsconfig.json or null if not found
*/

@@ -19,59 +18,54 @@ export async function find(filename, options) {

const root = options?.root ? path.resolve(options.root) : null;
/** @type {(result: string|null)=>void}*/
let resolvePathPromise;
/** @type {((result: string|null,err?: ErrnoException)=>void)} */
let done;
/** @type {Promise<string|null> | string | null}*/
const pathPromise = new Promise((r) => {
resolvePathPromise = r;
});
while (dir) {
if (cache) {
if (cache.hasTSConfigPath(dir)) {
const cached = cache.getTSConfigPath(dir);
if (cached.then) {
cached.then(resolvePathPromise);
} else {
resolvePathPromise(/**@type {string|null} */ (cached));
}
return pathPromise;
const promise = new Promise((resolve, reject) => {
done = (result, err) => {
if (err) {
reject(err);
} else {
cache.setTSConfigPath(dir, pathPromise);
resolve(result);
}
}
const tsconfig = await tsconfigInDir(dir);
if (tsconfig) {
resolvePathPromise(tsconfig);
return pathPromise;
} else {
const parent = path.dirname(dir);
if (root === dir || parent === dir) {
// reached root
break;
} else {
dir = parent;
}
}
}
resolvePathPromise(null);
throw new Error(`no tsconfig file found for ${filename}`);
};
});
findUp(dir, promise, done, options?.cache, root);
return promise;
}
/**
* test if tsconfig exists in dir
*
* @param {string} dir
* @returns {Promise<string|undefined>}
* @param {Promise<string|null>} promise
* @param {((result: string|null,err?: ErrnoException)=>void)} done
* @param {import('./cache.js').TSConfckCache} [cache]
* @param {string} [root]
*/
async function tsconfigInDir(dir) {
function findUp(dir, promise, done, cache, root) {
const tsconfig = path.join(dir, 'tsconfig.json');
try {
const stat = await fs.stat(tsconfig);
if (stat.isFile() || stat.isFIFO()) {
return tsconfig;
if (cache) {
if (cache.hasTSConfigPath(dir)) {
const cached = cache.getTSConfigPath(dir);
if (cached.then) {
cached.then(done).catch((err) => done(null, err));
} else {
done(/**@type {string|null} */ (cached));
}
} else {
cache.setTSConfigPath(dir, promise);
}
} catch (e) {
// ignore does not exist error
if (e.code !== 'ENOENT') {
throw e;
}
fs.stat(tsconfig, (err, stats) => {
if (stats && (stats.isFile() || stats.isFIFO())) {
done(tsconfig);
} else if (err?.code !== 'ENOENT') {
done(null, err);
} else {
let parent;
if (root === dir || (parent = path.dirname(dir)) === dir) {
done(null);
} else {
findUp(parent, promise, done, cache, root);
}
}
}
});
}

@@ -22,2 +22,3 @@ import path from 'path';

export async function parseNative(filename, options) {
/** @type {import('./cache.js').TSConfckCache} */
const cache = options?.cache;

@@ -31,5 +32,5 @@ if (cache?.hasParseResult(filename)) {

try {
tsconfigFile = await resolveTSConfig(filename);
tsconfigFile = await resolveTSConfig(filename, cache);
if (!tsconfigFile) {
tsconfigFile = await findNative(filename);
tsconfigFile = await findNative(filename, options);
}

@@ -46,5 +47,5 @@ } catch (e) {

} else {
tsconfigFile = await resolveTSConfig(filename);
tsconfigFile = await resolveTSConfig(filename, cache);
if (!tsconfigFile) {
tsconfigFile = await findNative(filename);
tsconfigFile = await findNative(filename, options);
}

@@ -56,3 +57,3 @@ }

if (cache?.hasParseResult(tsconfigFile)) {
result = cache.getParseResult(tsconfigFile);
result = await cache.getParseResult(tsconfigFile);
} else {

@@ -59,0 +60,0 @@ const ts = await loadTS();

import path from 'path';
import { promises as fs } from 'fs';
import { promises as fs } from 'node:fs';
import { createRequire } from 'module';

@@ -14,6 +14,11 @@ import { find } from './find.js';

const not_found_result = {
tsconfigFile: null,
tsconfig: {}
};
/**
* parse the closest tsconfig.json file
*
* @param {string} filename - path to a tsconfig.json or a .ts source file (absolute or relative to cwd)
* @param {string} filename - path to a tsconfig .json or a source file or directory (absolute or relative to cwd)
* @param {import('./public.d.ts').TSConfckParseOptions} [options] - options

@@ -24,2 +29,3 @@ * @returns {Promise<import('./public.d.ts').TSConfckParseResult>}

export async function parse(filename, options) {
/** @type {import('./cache.js').TSConfckCache} */
const cache = options?.cache;

@@ -37,17 +43,8 @@ if (cache?.hasParseResult(filename)) {

let tsconfigFile;
if (options?.resolveWithEmptyIfConfigNotFound) {
try {
tsconfigFile = (await resolveTSConfig(filename)) || (await find(filename, options));
} catch (e) {
const notFoundResult = {
tsconfigFile: 'no_tsconfig_file_found',
tsconfig: {}
};
resolveConfigPromise(notFoundResult);
return configPromise;
}
} else {
tsconfigFile = (await resolveTSConfig(filename)) || (await find(filename, options));
let tsconfigFile = (await resolveTSConfig(filename, cache)) || (await find(filename, options));
if (!tsconfigFile) {
resolveConfigPromise(not_found_result);
return configPromise;
}
let result;

@@ -67,3 +64,3 @@ if (filename !== tsconfigFile && cache?.hasParseResult(tsconfigFile)) {

* @param {string} tsconfigFile - path to tsconfig file
* @param {TSConfckCache} cache - cache
* @param {import('./cache.js').TSConfckCache} [cache] - cache
* @param {boolean} [skipCache] - skip cache

@@ -131,3 +128,3 @@ * @returns {Promise<import('./public.d.ts').TSConfckParseResult>}

* @param {import('./public.d.ts').TSConfckParseResult} result
* @param {TSConfckCache} [cache]
* @param {import('./cache.js').TSConfckCache}[cache]
* @returns {Promise<void>}

@@ -134,0 +131,0 @@ */

@@ -1,2 +0,2 @@

import { TSConfckCache } from './cache';
import { TSConfckCache } from './cache.js';

@@ -9,3 +9,3 @@ export interface TSConfckFindOptions {

*/
cache?: TSConfckCache;
cache?: TSConfckCache<TSConfckParseResult | TSConfckParseNativeResult>;

@@ -20,2 +20,6 @@ /**

export interface TSConfckParseOptions extends TSConfckFindOptions {
// same as find options
}
export interface TSConfckFindAllOptions {

@@ -30,10 +34,2 @@ /**

export interface TSConfckParseOptions extends TSConfckFindOptions {
/**
* treat missing tsconfig as empty result instead of an error
* parse resolves with { filename: 'no_tsconfig_file_found',tsconfig:{}} instead of reject with error
*/
resolveWithEmptyIfConfigNotFound?: boolean;
}
export interface TSConfckParseResult {

@@ -106,3 +102,1 @@ /**

}
export type Awaitable<T> = Promise<T> | T;

@@ -1,3 +0,3 @@

import path from 'path';
import { promises as fs } from 'fs';
import path from 'node:path';
import { promises as fs } from 'node:fs';

@@ -14,2 +14,4 @@ const POSIX_SEP_RE = new RegExp('\\' + path.posix.sep, 'g');

const IS_POSIX = path.posix.sep === path.sep;
/**

@@ -30,5 +32,6 @@ * loads typescript async to avoid direct dependency

* @param {string} filename
* @param {import('./cache.js').TSConfckCache} [cache]
* @returns {Promise<string|void>}
*/
export async function resolveTSConfig(filename) {
export async function resolveTSConfig(filename, cache) {
if (path.extname(filename) !== '.json') {

@@ -38,2 +41,15 @@ return;

const tsconfig = path.resolve(filename);
if (cache) {
if (cache.hasParseResult(tsconfig)) {
return tsconfig;
}
if (path.basename(tsconfig) === 'tsconfig.json') {
const dir = path.dirname(tsconfig);
if (cache.hasTSConfigPath(dir)) {
const cached = await cache.getTSConfigPath(dir);
return cached === tsconfig ? tsconfig : undefined;
}
}
}
try {

@@ -63,7 +79,9 @@ const stat = await fs.stat(tsconfig);

*/
export function posix2native(filename) {
return path.posix.sep !== path.sep && filename.includes(path.posix.sep)
? filename.replace(POSIX_SEP_RE, path.sep)
: filename;
}
export const posix2native = IS_POSIX
? (s) => s
: (filename) => {
return filename.includes(path.posix.sep)
? filename.replace(POSIX_SEP_RE, path.sep)
: filename;
};

@@ -80,7 +98,9 @@ /**

*/
export function native2posix(filename) {
return path.posix.sep !== path.sep && filename.includes(path.sep)
? filename.replace(NATIVE_SEP_RE, path.posix.sep)
: filename;
}
export const native2posix = IS_POSIX
? (s) => s
: (filename) => {
return filename.includes(path.sep)
? filename.replace(NATIVE_SEP_RE, path.posix.sep)
: filename;
};

@@ -97,3 +117,3 @@ /**

export function resolve2posix(dir, filename) {
if (path.sep === path.posix.sep) {
if (IS_POSIX) {
return dir ? path.resolve(dir, filename) : path.resolve(filename);

@@ -100,0 +120,0 @@ }

@@ -7,5 +7,5 @@ declare module 'tsconfck' {

* @param options - options
* @returns absolute path to closest tsconfig.json
* @returns absolute path to closest tsconfig.json or null if not found
*/
export function find(filename: string, options?: TSConfckFindOptions | undefined): Promise<string>;
export function find(filename: string, options?: TSConfckFindOptions | undefined): Promise<string | null>;
/**

@@ -36,8 +36,7 @@ * find all tsconfig.json files in dir

export function findNative(filename: string, options?: TSConfckFindOptions | undefined): Promise<string>;
export class TSConfckCache {
export class TSConfckCache<T> {
/**
* clear cache, use this if you have a long running process and tsconfig files have been added,changed or deleted
* await it to ensure all find and parse calls are settled before continuing
*/
clear(): Promise<void>;
clear(): void;
/**

@@ -50,3 +49,3 @@ * has cached closest tsconfig for files in dir

* */
getTSConfigPath(dir: string): Awaitable<string | null>;
getTSConfigPath(dir: string): Promise<string | null> | string | null;
/**

@@ -59,8 +58,6 @@ * has parsed tsconfig for file

* */
getParseResult(file: string): Awaitable<TSConfckParseResult | TSConfckParseNativeResult>;
getParseResult(file: string): Promise<T> | T;
private setParseResult;
private deleteParseResult;
private setTSConfigPath;

@@ -72,3 +69,3 @@ #private;

*
* @param filename - path to a tsconfig.json or a .ts source file (absolute or relative to cwd)
* @param filename - path to a tsconfig .json or a source file or directory (absolute or relative to cwd)
* @param options - options

@@ -139,3 +136,3 @@ * */

*/
cache?: TSConfckCache;
cache?: TSConfckCache<TSConfckParseResult | TSConfckParseNativeResult>;

@@ -150,2 +147,6 @@ /**

interface TSConfckParseOptions extends TSConfckFindOptions {
// same as find options
}
interface TSConfckFindAllOptions {

@@ -160,10 +161,2 @@ /**

interface TSConfckParseOptions extends TSConfckFindOptions {
/**
* treat missing tsconfig as empty result instead of an error
* parse resolves with { filename: 'no_tsconfig_file_found',tsconfig:{}} instead of reject with error
*/
resolveWithEmptyIfConfigNotFound?: boolean;
}
interface TSConfckParseResult {

@@ -236,6 +229,4 @@ /**

}
type Awaitable<T> = Promise<T> | T;
}
//# sourceMappingURL=index.d.ts.map

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc