load-oxfmt-config 0.3.1 → 0.4.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/README.md +1 -0
- package/dist/index.mjs +102 -5
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -287,6 +287,7 @@ The loader reads the nearest `.editorconfig` file and maps the subset of fields
|
|
|
287
287
|
- `indent_size` / `tab_width` → `tabWidth`
|
|
288
288
|
- `max_line_length` → `printWidth`
|
|
289
289
|
- `insert_final_newline` → `insertFinalNewline`
|
|
290
|
+
- `quote_type` → `singleQuote`
|
|
290
291
|
|
|
291
292
|
Glob sections such as `[*.ts]` are converted into returned `overrides` entries.
|
|
292
293
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile, stat } from "node:fs/promises";
|
|
2
2
|
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
|
-
import { interopDefault } from "@ntnyq/utils";
|
|
4
|
+
import { interopDefault, isBoolean, isNumber, isObject } from "@ntnyq/utils";
|
|
5
5
|
import { parse } from "jsonc-parser";
|
|
6
6
|
import { parseBuffer } from "editorconfig";
|
|
7
7
|
//#region src/constants.ts
|
|
@@ -24,23 +24,57 @@ const EDITORCONFIG_FILE = ".editorconfig";
|
|
|
24
24
|
const EDITORCONFIG_GLOBAL_SECTION_NAMES = ["*", "**"];
|
|
25
25
|
//#endregion
|
|
26
26
|
//#region src/editorconfig.ts
|
|
27
|
+
/**
|
|
28
|
+
* Builds the cache key used for resolved EditorConfig lookups.
|
|
29
|
+
*
|
|
30
|
+
* @param resolveKey - The base resolution key for the current lookup.
|
|
31
|
+
* @returns The namespaced cache key for EditorConfig resolution.
|
|
32
|
+
*/
|
|
27
33
|
function getEditorconfigResolveCacheKey(resolveKey) {
|
|
28
34
|
return `editorconfig::${resolveKey}`;
|
|
29
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Determines the directory that should be used to search for a nearby .editorconfig file.
|
|
38
|
+
*
|
|
39
|
+
* @param cwd - The current working directory for the lookup.
|
|
40
|
+
* @param configPath - An optional config path used to anchor the search.
|
|
41
|
+
* @returns The directory where EditorConfig discovery should begin.
|
|
42
|
+
*/
|
|
30
43
|
function getEditorconfigSearchDir(cwd, configPath) {
|
|
31
44
|
if (!configPath) return cwd;
|
|
32
45
|
return dirname(isAbsolute(configPath) ? configPath : join(cwd, configPath));
|
|
33
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Merges root-level EditorConfig options with oxfmt config options.
|
|
49
|
+
*
|
|
50
|
+
* @param oxfmtConfig - The explicit oxfmt options.
|
|
51
|
+
* @param editorconfigRootOptions - Root options derived from .editorconfig.
|
|
52
|
+
* @returns A single root options object where oxfmt takes precedence.
|
|
53
|
+
*/
|
|
34
54
|
function mergeRootOptions(oxfmtConfig, editorconfigRootOptions) {
|
|
35
55
|
return {
|
|
36
56
|
...editorconfigRootOptions,
|
|
37
57
|
...oxfmtConfig
|
|
38
58
|
};
|
|
39
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Merges EditorConfig-derived overrides with explicit oxfmt overrides.
|
|
62
|
+
*
|
|
63
|
+
* @param oxfmtOverrides - Overrides declared in the oxfmt config.
|
|
64
|
+
* @param editorconfigOverrides - Overrides derived from .editorconfig sections.
|
|
65
|
+
* @returns The merged overrides array, or undefined when no overrides exist.
|
|
66
|
+
*/
|
|
40
67
|
function mergeOverrides(oxfmtOverrides, editorconfigOverrides) {
|
|
41
68
|
const mergedOverrides = [...editorconfigOverrides, ...oxfmtOverrides || []];
|
|
42
69
|
return mergedOverrides.length > 0 ? mergedOverrides : void 0;
|
|
43
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolves the nearest .editorconfig file starting from a directory and optionally walking upward.
|
|
73
|
+
*
|
|
74
|
+
* @param startDir - The directory where the search starts.
|
|
75
|
+
* @param onlyCwd - When true, only checks the starting directory.
|
|
76
|
+
* @returns The resolved .editorconfig path, or undefined when none is found.
|
|
77
|
+
*/
|
|
44
78
|
async function resolveEditorconfigPath(startDir, onlyCwd = false) {
|
|
45
79
|
let currentDir = startDir;
|
|
46
80
|
while (true) {
|
|
@@ -54,19 +88,59 @@ async function resolveEditorconfigPath(startDir, onlyCwd = false) {
|
|
|
54
88
|
currentDir = parentDir;
|
|
55
89
|
}
|
|
56
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Normalizes a file path to POSIX separators for glob compatibility.
|
|
93
|
+
*
|
|
94
|
+
* @param path - The path to normalize.
|
|
95
|
+
* @returns The path with forward slashes.
|
|
96
|
+
*/
|
|
57
97
|
function toPosixPath(path) {
|
|
58
98
|
return path.replaceAll("\\", "/");
|
|
59
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Checks whether an EditorConfig section should be treated as a global section.
|
|
102
|
+
*
|
|
103
|
+
* @param sectionName - The section name parsed from .editorconfig.
|
|
104
|
+
* @returns True when the section applies globally.
|
|
105
|
+
*/
|
|
60
106
|
function isEditorconfigGlobalSection(sectionName) {
|
|
61
107
|
return Boolean(sectionName && EDITORCONFIG_GLOBAL_SECTION_NAMES.includes(sectionName));
|
|
62
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Parses an EditorConfig boolean string.
|
|
111
|
+
*
|
|
112
|
+
* @param value - The raw EditorConfig value.
|
|
113
|
+
* @returns The parsed boolean, or undefined when the value is unsupported.
|
|
114
|
+
*/
|
|
63
115
|
function parseEditorconfigBoolean(value) {
|
|
64
116
|
if (value === "true") return true;
|
|
65
117
|
if (value === "false") return false;
|
|
66
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Parses the end-of-line style supported by oxfmt.
|
|
121
|
+
*
|
|
122
|
+
* @param value - The raw EditorConfig end_of_line value.
|
|
123
|
+
* @returns The normalized line ending value, or undefined when unsupported.
|
|
124
|
+
*/
|
|
67
125
|
function parseEditorconfigEndOfLine(value) {
|
|
68
126
|
if (value === "lf" || value === "crlf" || value === "cr") return value;
|
|
69
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Parses the single quote preference from an EditorConfig section.
|
|
130
|
+
*
|
|
131
|
+
* @param value - The raw EditorConfig value for single quote preference.
|
|
132
|
+
* @returns True if single quotes are preferred, false if double quotes are preferred, or undefined when auto.
|
|
133
|
+
*/
|
|
134
|
+
function parseEditorconfigQuoteType(value) {
|
|
135
|
+
if (value === "single") return true;
|
|
136
|
+
if (value === "double") return false;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Resolves the effective tab width from an EditorConfig section.
|
|
140
|
+
*
|
|
141
|
+
* @param section - The parsed EditorConfig section body.
|
|
142
|
+
* @returns The resolved tab width, or undefined when no numeric value is available.
|
|
143
|
+
*/
|
|
70
144
|
function parseEditorconfigTabWidth(section) {
|
|
71
145
|
const indentSize = section["indent_size"];
|
|
72
146
|
const tabWidth = section["tab_width"];
|
|
@@ -79,27 +153,50 @@ function parseEditorconfigTabWidth(section) {
|
|
|
79
153
|
if (Number.isFinite(parsedTabWidth)) return parsedTabWidth;
|
|
80
154
|
}
|
|
81
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Maps a parsed EditorConfig section to the subset of oxfmt formatter options it supports.
|
|
158
|
+
*
|
|
159
|
+
* @param section - The parsed EditorConfig section body.
|
|
160
|
+
* @returns Formatter options derived from the section.
|
|
161
|
+
*/
|
|
82
162
|
function mapEditorconfigSectionToOptions(section) {
|
|
83
163
|
const options = {};
|
|
84
164
|
const endOfLine = parseEditorconfigEndOfLine(section["end_of_line"]);
|
|
85
165
|
if (endOfLine) options.endOfLine = endOfLine;
|
|
86
166
|
if (section["indent_style"] === "tab") options.useTabs = true;
|
|
87
167
|
else if (section["indent_style"] === "space") options.useTabs = false;
|
|
168
|
+
const singleQuote = parseEditorconfigQuoteType(section["quote_type"]);
|
|
169
|
+
if (isBoolean(singleQuote)) options.singleQuote = singleQuote;
|
|
88
170
|
const tabWidth = parseEditorconfigTabWidth(section);
|
|
89
|
-
if (
|
|
171
|
+
if (isNumber(tabWidth)) options.tabWidth = tabWidth;
|
|
90
172
|
if (section["max_line_length"] && section["max_line_length"] !== "unset") {
|
|
91
173
|
const parsedPrintWidth = Number(section["max_line_length"]);
|
|
92
174
|
if (Number.isFinite(parsedPrintWidth)) options.printWidth = parsedPrintWidth;
|
|
93
175
|
}
|
|
94
176
|
const insertFinalNewline = parseEditorconfigBoolean(section["insert_final_newline"]);
|
|
95
|
-
if (
|
|
177
|
+
if (isBoolean(insertFinalNewline)) options.insertFinalNewline = insertFinalNewline;
|
|
96
178
|
return options;
|
|
97
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Rebases an EditorConfig section pattern from the config directory to the target anchor directory.
|
|
182
|
+
*
|
|
183
|
+
* @param pattern - The original EditorConfig section pattern.
|
|
184
|
+
* @param editorconfigDir - The directory containing the .editorconfig file.
|
|
185
|
+
* @param anchorDir - The directory used as the override pattern base.
|
|
186
|
+
* @returns The rebased glob pattern.
|
|
187
|
+
*/
|
|
98
188
|
function rebaseEditorconfigPattern(pattern, editorconfigDir, anchorDir) {
|
|
99
189
|
const relativePrefix = toPosixPath(relative(anchorDir, editorconfigDir));
|
|
100
190
|
if (!relativePrefix || relativePrefix === ".") return pattern;
|
|
101
191
|
return `${relativePrefix}/${pattern.replace(/^\//, "")}`;
|
|
102
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Reads a .editorconfig file and converts it into root options and override entries.
|
|
195
|
+
*
|
|
196
|
+
* @param editorconfigPath - The absolute path to the .editorconfig file.
|
|
197
|
+
* @param anchorDir - The directory used to rebase section patterns.
|
|
198
|
+
* @returns Parsed EditorConfig data ready to merge into oxfmt config.
|
|
199
|
+
*/
|
|
103
200
|
async function readEditorconfigFromFile(editorconfigPath, anchorDir) {
|
|
104
201
|
const parsedSections = parseBuffer(await readFile(editorconfigPath));
|
|
105
202
|
const editorconfigDir = dirname(editorconfigPath);
|
|
@@ -223,8 +320,8 @@ async function loadOxfmtConfig(options = {}) {
|
|
|
223
320
|
const cwd = options.cwd || process.cwd();
|
|
224
321
|
const editorconfig = options.editorconfig ?? true;
|
|
225
322
|
const useEditorconfig = editorconfig !== false;
|
|
226
|
-
const onlyCwd = useEditorconfig &&
|
|
227
|
-
const editorconfigCwd = useEditorconfig &&
|
|
323
|
+
const onlyCwd = useEditorconfig && isObject(editorconfig) ? editorconfig.onlyCwd ?? false : false;
|
|
324
|
+
const editorconfigCwd = useEditorconfig && isObject(editorconfig) ? editorconfig.cwd : void 0;
|
|
228
325
|
const resolveKey = getResolveCacheKey(cwd, options.configPath);
|
|
229
326
|
const editorconfigSearchDir = editorconfigCwd || getEditorconfigSearchDir(cwd, options.configPath);
|
|
230
327
|
const editorconfigResolveKey = editorconfigCwd ? getEditorconfigResolveCacheKey(`${editorconfigCwd}::${options.configPath || ""}`) : getEditorconfigResolveCacheKey(resolveKey);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "load-oxfmt-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Load oxfmt config files and merge supported .editorconfig options.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"editorconfig",
|
|
@@ -39,23 +39,23 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@ntnyq/utils": "^0.
|
|
42
|
+
"@ntnyq/utils": "^0.12.0",
|
|
43
43
|
"editorconfig": "^3.0.2",
|
|
44
44
|
"jiti": "^2.6.1",
|
|
45
45
|
"jsonc-parser": "^3.3.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@ntnyq/tsconfig": "^3.1.0",
|
|
49
|
-
"@types/node": "^25.
|
|
50
|
-
"@typescript/native-preview": "^7.0.0-dev.
|
|
49
|
+
"@types/node": "^25.6.0",
|
|
50
|
+
"@typescript/native-preview": "^7.0.0-dev.20260413.1",
|
|
51
51
|
"bumpp": "^11.0.1",
|
|
52
52
|
"husky": "^9.1.7",
|
|
53
|
-
"nano-staged": "^0.
|
|
53
|
+
"nano-staged": "^1.0.2",
|
|
54
54
|
"npm-run-all2": "^8.0.4",
|
|
55
|
-
"oxfmt": "^0.
|
|
56
|
-
"oxlint": "^1.
|
|
57
|
-
"tsdown": "^0.21.
|
|
58
|
-
"vitest": "^4.1.
|
|
55
|
+
"oxfmt": "^0.45.0",
|
|
56
|
+
"oxlint": "^1.60.0",
|
|
57
|
+
"tsdown": "^0.21.8",
|
|
58
|
+
"vitest": "^4.1.4"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"oxfmt": ">=0.41.0"
|