load-oxfmt-config 0.13.0 → 0.14.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/dist/index.d.mts +49 -22
- package/dist/index.mjs +47 -12
- package/package.json +7 -7
package/dist/index.d.mts
CHANGED
|
@@ -187,27 +187,6 @@ interface IsOxfmtIgnoredResult {
|
|
|
187
187
|
reason?: 'default-dir' | 'lockfile' | 'gitignore' | 'git-info-exclude' | 'prettierignore' | 'ignore-path' | 'config-ignore-patterns';
|
|
188
188
|
}
|
|
189
189
|
//#endregion
|
|
190
|
-
//#region src/config-file.d.ts
|
|
191
|
-
/**
|
|
192
|
-
* Resolve the oxfmt config file path.
|
|
193
|
-
*
|
|
194
|
-
* - If `configPath` is provided, absolute paths are returned as-is;
|
|
195
|
-
* relative paths are joined to `cwd`.
|
|
196
|
-
* - Otherwise, walk upward from `cwd` to find known filenames.
|
|
197
|
-
*
|
|
198
|
-
* @param cwd - Starting directory for resolution.
|
|
199
|
-
* @param configPath - Optional explicit path.
|
|
200
|
-
* @returns Absolute path to config file, or undefined when not found.
|
|
201
|
-
*
|
|
202
|
-
* @example
|
|
203
|
-
* ```ts
|
|
204
|
-
* import { resolveOxfmtrcPath } from 'load-oxfmt-config'
|
|
205
|
-
*
|
|
206
|
-
* const path = await resolveOxfmtrcPath(process.cwd())
|
|
207
|
-
* ```
|
|
208
|
-
*/
|
|
209
|
-
declare function resolveOxfmtrcPath(cwd: string, configPath?: string): Promise<string | undefined>;
|
|
210
|
-
//#endregion
|
|
211
190
|
//#region src/core.d.ts
|
|
212
191
|
/**
|
|
213
192
|
* Resolve config + editorconfig and return merged config with metadata.
|
|
@@ -244,4 +223,52 @@ declare function loadOxfmtConfig(options?: LoadOxfmtConfigOptions): Promise<Load
|
|
|
244
223
|
*/
|
|
245
224
|
declare function isOxfmtIgnored(options: IsOxfmtIgnoredOptions): Promise<IsOxfmtIgnoredResult>;
|
|
246
225
|
//#endregion
|
|
247
|
-
|
|
226
|
+
//#region src/config.d.ts
|
|
227
|
+
/**
|
|
228
|
+
* Build a cache key for path resolution (cwd + configPath).
|
|
229
|
+
*
|
|
230
|
+
* @param cwd - Current working directory.
|
|
231
|
+
* @param configPath - Optional config path.
|
|
232
|
+
* @returns Cache key for resolve cache.
|
|
233
|
+
*/
|
|
234
|
+
declare function getResolveCacheKey(cwd: string, configPath?: string): string;
|
|
235
|
+
/**
|
|
236
|
+
* Build a cache key for config content; prefixes missing entries.
|
|
237
|
+
*
|
|
238
|
+
* @param resolvedPath - Resolved oxfmt config path.
|
|
239
|
+
* @param editorconfigPath - Resolved editorconfig path.
|
|
240
|
+
* @param resolveKey - Resolution cache key.
|
|
241
|
+
* @returns Cache key for config content cache.
|
|
242
|
+
*/
|
|
243
|
+
declare function getConfigCacheKey(resolvedPath: string | undefined, editorconfigPath: string | undefined, resolveKey: string): string;
|
|
244
|
+
/**
|
|
245
|
+
* Resolve the oxfmt config file path.
|
|
246
|
+
*
|
|
247
|
+
* - If `configPath` is provided, absolute paths are returned as-is;
|
|
248
|
+
* relative paths are joined to `cwd`.
|
|
249
|
+
* - Otherwise, walk upward from `cwd` to find known filenames.
|
|
250
|
+
*
|
|
251
|
+
* @param cwd - Starting directory for resolution.
|
|
252
|
+
* @param configPath - Optional explicit path.
|
|
253
|
+
* @returns Absolute path to config file, or undefined when not found.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```ts
|
|
257
|
+
* import { resolveOxfmtrcPath } from 'load-oxfmt-config'
|
|
258
|
+
*
|
|
259
|
+
* const path = await resolveOxfmtrcPath(process.cwd())
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
declare function resolveOxfmtrcPath(cwd: string, configPath?: string): Promise<string | undefined>;
|
|
263
|
+
/**
|
|
264
|
+
* Read and parse an oxfmt config file.
|
|
265
|
+
*
|
|
266
|
+
* @param resolvedPath - Absolute path to config file.
|
|
267
|
+
* @param options - Config loading options.
|
|
268
|
+
* @returns Parsed config object.
|
|
269
|
+
*/
|
|
270
|
+
declare function readConfigFromFile(resolvedPath: string, options?: {
|
|
271
|
+
useCache?: boolean;
|
|
272
|
+
}): Promise<OxfmtOptions>;
|
|
273
|
+
//#endregion
|
|
274
|
+
export { EditorconfigOption, IsOxfmtIgnoredOptions, IsOxfmtIgnoredResult, LoadOxfmtConfigOptions, LoadOxfmtConfigResult, OxfmtConfigOverride, OxfmtOptions, getConfigCacheKey, getResolveCacheKey, isOxfmtIgnored, loadOxfmtConfig, readConfigFromFile, resolveOxfmtrcPath };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
|
-
import { interopDefault, isBoolean, isNumber, isObject } from "@ntnyq/utils";
|
|
4
|
+
import { hasOwn, interopDefault, isBoolean, isNumber, isObject, isRecord, isString, isUndefined } from "@ntnyq/utils";
|
|
5
5
|
import { readFile, stat } from "node:fs/promises";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
import { parse, printParseErrorCode } from "jsonc-parser";
|
|
@@ -75,7 +75,7 @@ const EDITORCONFIG_FILE = ".editorconfig";
|
|
|
75
75
|
*/
|
|
76
76
|
const EDITORCONFIG_GLOBAL_SECTION_NAMES = ["*"];
|
|
77
77
|
//#endregion
|
|
78
|
-
//#region src/config
|
|
78
|
+
//#region src/config.ts
|
|
79
79
|
/**
|
|
80
80
|
* CommonJS require scoped to this ESM module for loading `.cjs` config files.
|
|
81
81
|
*/
|
|
@@ -99,7 +99,18 @@ const syntaxFallbackMessages = [
|
|
|
99
99
|
* @returns True when the value can be treated as an oxfmt options object.
|
|
100
100
|
*/
|
|
101
101
|
function isConfigObject(value) {
|
|
102
|
-
return
|
|
102
|
+
return isRecord(value);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Read a parsed JSON-like config value as an oxfmt config object.
|
|
106
|
+
*
|
|
107
|
+
* @param config - Runtime config value.
|
|
108
|
+
* @returns Oxfmt config object.
|
|
109
|
+
* @throws When the config value is not an object.
|
|
110
|
+
*/
|
|
111
|
+
function readParsedConfigObject(config) {
|
|
112
|
+
if (!isConfigObject(config)) throw new Error("Configuration file must be an object.");
|
|
113
|
+
return config;
|
|
103
114
|
}
|
|
104
115
|
/**
|
|
105
116
|
* Read the default export from a JavaScript or TypeScript config module.
|
|
@@ -109,7 +120,7 @@ function isConfigObject(value) {
|
|
|
109
120
|
* @throws When the module has no default export or the default export is not an object.
|
|
110
121
|
*/
|
|
111
122
|
function readConfigDefaultExport(mod) {
|
|
112
|
-
if (!
|
|
123
|
+
if (!hasOwn(mod, "default")) throw new Error("Configuration file has no default export.");
|
|
113
124
|
const config = mod["default"];
|
|
114
125
|
if (!isConfigObject(config)) throw new Error("Configuration file must have a default export that is an object.");
|
|
115
126
|
return config;
|
|
@@ -155,7 +166,7 @@ async function getFreshImportCacheKey(resolvedPath) {
|
|
|
155
166
|
* @returns Error code when present.
|
|
156
167
|
*/
|
|
157
168
|
function getErrorCode(error) {
|
|
158
|
-
return
|
|
169
|
+
return isObject(error) && "code" in error && isString(error.code) ? error.code : void 0;
|
|
159
170
|
}
|
|
160
171
|
/**
|
|
161
172
|
* Check whether a loader error should continue the JS config fallback chain.
|
|
@@ -321,15 +332,15 @@ async function readConfigFromFile(resolvedPath, options = {}) {
|
|
|
321
332
|
});
|
|
322
333
|
if (parseErrors.length > 0) {
|
|
323
334
|
const firstError = parseErrors[0];
|
|
324
|
-
const errorCode = firstError
|
|
335
|
+
const errorCode = isUndefined(firstError) ? "Unknown" : printParseErrorCode(firstError.error);
|
|
325
336
|
throw new Error(`Invalid JSONC syntax: ${errorCode}`);
|
|
326
337
|
}
|
|
327
|
-
return parsed
|
|
338
|
+
return readParsedConfigObject(isUndefined(parsed) && content.trim() === "" ? {} : parsed);
|
|
328
339
|
}
|
|
329
|
-
if (extension === ".json") return JSON.parse(content);
|
|
330
|
-
if (!extension) return JSON.parse(content);
|
|
340
|
+
if (extension === ".json") return readParsedConfigObject(JSON.parse(content));
|
|
341
|
+
if (!extension) return readParsedConfigObject(JSON.parse(content));
|
|
331
342
|
if (!OXFMT_EXPLICIT_CONFIG_EXTENSIONS.includes(extension)) throw new Error(`Unsupported oxfmt config extension "${extension}" at ${resolvedPath}`);
|
|
332
|
-
return JSON.parse(content);
|
|
343
|
+
return readParsedConfigObject(JSON.parse(content));
|
|
333
344
|
}
|
|
334
345
|
//#endregion
|
|
335
346
|
//#region src/utils.ts
|
|
@@ -757,6 +768,29 @@ async function hasGitEntry(dir) {
|
|
|
757
768
|
}
|
|
758
769
|
}
|
|
759
770
|
/**
|
|
771
|
+
* Resolve the git info exclude file from a repo root.
|
|
772
|
+
*
|
|
773
|
+
* Worktrees and submodules store `.git` as a file containing a `gitdir:` pointer.
|
|
774
|
+
*
|
|
775
|
+
* @param repoRoot - Git repository working tree root.
|
|
776
|
+
* @returns Absolute path to the git info exclude file, or undefined when unavailable.
|
|
777
|
+
*/
|
|
778
|
+
async function resolveGitInfoExcludePath(repoRoot) {
|
|
779
|
+
const gitEntryPath = join(repoRoot, ".git");
|
|
780
|
+
try {
|
|
781
|
+
const stats = await stat(gitEntryPath);
|
|
782
|
+
if (stats.isDirectory()) return join(gitEntryPath, "info", "exclude");
|
|
783
|
+
if (!stats.isFile()) return;
|
|
784
|
+
const gitdir = (await readFile(gitEntryPath, "utf8")).split(/\r?\n/u).find((line) => line.startsWith("gitdir:"))?.slice(7).trim();
|
|
785
|
+
if (!gitdir) return;
|
|
786
|
+
return join(isAbsolute(gitdir) ? gitdir : resolve(repoRoot, gitdir), "info", "exclude");
|
|
787
|
+
} catch (error) {
|
|
788
|
+
const code = error.code;
|
|
789
|
+
if (code === "ENOENT" || code === "ENOTDIR") return;
|
|
790
|
+
throw error;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
760
794
|
* Find the nearest git repo root by walking up from a start directory.
|
|
761
795
|
*
|
|
762
796
|
* @param fromDir - Directory to start from.
|
|
@@ -851,7 +885,8 @@ async function isOxfmtIgnored(options) {
|
|
|
851
885
|
reason: "gitignore"
|
|
852
886
|
};
|
|
853
887
|
if (repoRoot) {
|
|
854
|
-
|
|
888
|
+
const infoExcludePath = await resolveGitInfoExcludePath(repoRoot);
|
|
889
|
+
if (infoExcludePath && await matchIgnoreFile(filepath, infoExcludePath, useCache, repoRoot)) return {
|
|
855
890
|
ignored: true,
|
|
856
891
|
reason: "git-info-exclude"
|
|
857
892
|
};
|
|
@@ -881,4 +916,4 @@ async function isOxfmtIgnored(options) {
|
|
|
881
916
|
return { ignored: false };
|
|
882
917
|
}
|
|
883
918
|
//#endregion
|
|
884
|
-
export { isOxfmtIgnored, loadOxfmtConfig, resolveOxfmtrcPath };
|
|
919
|
+
export { getConfigCacheKey, getResolveCacheKey, isOxfmtIgnored, loadOxfmtConfig, readConfigFromFile, resolveOxfmtrcPath };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "load-oxfmt-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Load and resolve oxfmt configuration files, including explicit JS/TS config paths, and merge supported `.editorconfig` settings for Oxfmt.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"editorconfig",
|
|
@@ -50,19 +50,19 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@ntnyq/tsconfig": "^3.1.0",
|
|
53
|
-
"@types/node": "^26.0
|
|
54
|
-
"@typescript/native-preview": "^7.0.0-dev.
|
|
53
|
+
"@types/node": "^26.1.0",
|
|
54
|
+
"@typescript/native-preview": "^7.0.0-dev.20260706.1",
|
|
55
55
|
"bumpp": "^11.1.0",
|
|
56
56
|
"husky": "^9.1.7",
|
|
57
57
|
"nano-staged": "^1.0.2",
|
|
58
58
|
"npm-run-all2": "^9.0.2",
|
|
59
|
-
"oxfmt": "^0.
|
|
60
|
-
"oxlint": "^1.
|
|
59
|
+
"oxfmt": "^0.58.0",
|
|
60
|
+
"oxlint": "^1.73.0",
|
|
61
61
|
"tsdown": "^0.22.3",
|
|
62
|
-
"vitest": "^4.1.
|
|
62
|
+
"vitest": "^4.1.10"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"oxfmt": ">=0.
|
|
65
|
+
"oxfmt": ">=0.58.0"
|
|
66
66
|
},
|
|
67
67
|
"nano-staged": {
|
|
68
68
|
"*.{js,ts,mjs,tsx}": "oxlint --fix",
|