yamllint-js 0.2.1 β†’ 0.2.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.3](https://github.com/kimzuni-labs/yamllint-js/compare/v0.2.2...v0.2.3) (2026-02-19)
4
+
5
+
6
+ ### ✨ Features
7
+
8
+ * support options on loadYamlLintConfig ([9f67bea](https://github.com/kimzuni-labs/yamllint-js/commit/9f67beab94698b64c1b09c332a246d4099ff0cbc))
9
+
10
+
11
+ ### πŸ› Bug Fixes
12
+
13
+ * stopDir option on loadConfigFile ([9f67bea](https://github.com/kimzuni-labs/yamllint-js/commit/9f67beab94698b64c1b09c332a246d4099ff0cbc))
14
+ * throw on failure in loadConfigFile ([9f67bea](https://github.com/kimzuni-labs/yamllint-js/commit/9f67beab94698b64c1b09c332a246d4099ff0cbc))
15
+
16
+ ## [0.2.2](https://github.com/kimzuni-labs/yamllint-js/compare/v0.2.1...v0.2.2) (2026-02-19)
17
+
18
+
19
+ ### πŸ› Bug Fixes
20
+
21
+ * detection yamllint field in package.json ([#37](https://github.com/kimzuni-labs/yamllint-js/issues/37)) ([5fe02d7](https://github.com/kimzuni-labs/yamllint-js/commit/5fe02d73c299bba7a53edb90a56aa16fad4fc845))
22
+
3
23
  ## [0.2.1](https://github.com/kimzuni-labs/yamllint-js/compare/v0.2.0...v0.2.1) (2026-02-14)
4
24
 
5
25
 
package/README.md CHANGED
@@ -130,14 +130,15 @@ In addition to the yamllint configuration format,
130
130
  JavaScript and TypeScript configuration files are also supported:
131
131
 
132
132
  - [yamllint configuration files and environment variables](https://yamllint.readthedocs.io/en/stable/configuration.html):
133
- - [Cosmiconfig default search places](https://github.com/cosmiconfig/cosmiconfig/blob/a5a842547c13392ebb89a485b9e56d9f37e3cbd3/src/defaults.ts#L12-L32):
134
- + `package.json` (`"yamllint-js"` field), `yamllint-js.config.ts`, etc. (Not support `rc` files)
135
- + `package.json` (`"yamllint"` field), `.yamllintrc.json`, `yamllint.config.ts`, etc.
133
+ - `package.json` or js/ts config files
134
+ + `package.json` (`"yamllint-js"`, `"yamllint"` fields)
135
+ + `yamllint-js.config.js`, `.ts`, `.cjs`, `.mjs`
136
+ + `yamllint.config.js`, `.ts`, `.cjs`, `.mjs`
136
137
 
137
138
  Configuration can be easily defined with type hints, like:
138
139
 
139
140
  ```typescript
140
- /** @type {import("yamllint-js").UserConfig")} */
141
+ /** @type {import("yamllint-js").UserConfig} */
141
142
 
142
143
  const config = {/* ... */};
143
144
 
@@ -220,3 +221,4 @@ rules:
220
221
  ## License
221
222
 
222
223
  [GPL version 3](./LICENSE)
224
+ (port of [yamllint](https://github.com/adrienverge/yamllint))
package/dist/config.d.mts CHANGED
@@ -2,7 +2,6 @@ import { Level } from "./constants.mjs";
2
2
  import { Rule, RuleConf } from "./rules/types.mjs";
3
3
  import { RuleId } from "./rules/index.mjs";
4
4
  import { AllLevel, BuiltInExtendName, MaybeCamelCaseKeys, Prettify, ToCamelCaseKeys } from "./types.mjs";
5
- import * as cosmiconfig0 from "cosmiconfig";
6
5
  import { Ignore } from "ignore";
7
6
 
8
7
  //#region src/config.d.ts
@@ -70,6 +69,18 @@ declare class YamlLintConfig {
70
69
  enabledRules(filepath?: string): Rule[];
71
70
  extend(baseConfig: unknown): void;
72
71
  }
72
+ interface LoadConfigFileOptions {
73
+ /**
74
+ * @default process.cwd()
75
+ */
76
+ startDir?: string;
77
+ /**
78
+ * @default getHomedir()
79
+ *
80
+ * @see {@link getHomedir}
81
+ */
82
+ stopDir?: string;
83
+ }
73
84
  /**
74
85
  * Load YAML lint configuration from a file.
75
86
  *
@@ -78,9 +89,10 @@ declare class YamlLintConfig {
78
89
  * ```typescript
79
90
  * const autoDetected = await loadConfigFile();
80
91
  * const specified = await loadConfigFile("path/to/yamllint.yaml");
92
+ * const withOptions = await loadConfigFile({ startDir, stopDir });
81
93
  * ```
82
94
  */
83
- declare const loadConfigFile: (filepath?: string) => Promise<cosmiconfig0.CosmiconfigResult>;
95
+ declare const loadConfigFile: (filepath?: string | LoadConfigFileOptions) => Promise<unknown>;
84
96
  /**
85
97
  * Detect user global config file path.
86
98
  *
@@ -93,8 +105,12 @@ declare const loadConfigFile: (filepath?: string) => Promise<cosmiconfig0.Cosmic
93
105
  declare function detectUserGlobalConfig(): Promise<string | undefined>;
94
106
  /**
95
107
  * Load and return a fully resolved YamlLint configuration instance.
108
+ *
109
+ * - First, try to load config file from the current directory to user home directory.
110
+ * - If not found, try to load from the user global config file.
111
+ * - If not found, try to load from the default config.
96
112
  */
97
- declare function loadYamlLintConfig(): Promise<YamlLintConfig>;
113
+ declare function loadYamlLintConfig(options?: LoadConfigFileOptions): Promise<YamlLintConfig>;
98
114
  /**
99
115
  * if value is {@link AllLevel} or undefined
100
116
  * then convert to {@link Level} (undefined -> "error"),
package/dist/config.mjs CHANGED
@@ -1,14 +1,14 @@
1
- import { ALIASES, APP, CONFIG_SEARCH_PLACES, LEVELS, YAML_OPTIONS } from "./constants.mjs";
2
- import { formatErrorMessage, getHomedir, splitlines, toKebabCaseKeys } from "./utils.mjs";
1
+ import { ALIASES, COMMAND_NAMES, LEVELS, PY_YAMLLINT_CONFIG_FILES, YAML_OPTIONS } from "./constants.mjs";
2
+ import { formatErrorMessage, getHomedir, getNodeSearchPlaces, splitlines, toKebabCaseKeys } from "./utils.mjs";
3
3
  import { autoDecode, linesInFiles } from "./decoder.mjs";
4
4
  import { get } from "./rules/index.mjs";
5
5
  import fs from "node:fs/promises";
6
6
  import path from "node:path";
7
- import { cosmiconfig, defaultLoaders } from "cosmiconfig";
8
7
  import assert from "node:assert";
9
8
  import yaml from "yaml";
10
9
  import z from "zod";
11
10
  import ignore$1 from "ignore";
11
+ import { createJiti } from "jiti";
12
12
  /*!
13
13
  * Copyright (C) 2016 Adrien VergΓ©
14
14
  * Copyright (C) 2025 kimzuni
@@ -79,7 +79,7 @@ var YamlLintConfig = class YamlLintConfig {
79
79
  if (props._data !== void 0 || props.data !== void 0) this.#data = props._data ?? props.data;
80
80
  else try {
81
81
  if (props.content !== void 0) this.#data = yaml.parse(props.content, YAML_OPTIONS);
82
- else this.#data = await loadConfigFile(props.file).then((x) => x?.config);
82
+ else this.#data = await loadConfigFile(props.file);
83
83
  } catch (e) {
84
84
  throw new YamlLintConfigError(formatErrorMessage("invalid config: ", e));
85
85
  }
@@ -165,24 +165,55 @@ async function validateRuleConf(rule, config) {
165
165
  return conf;
166
166
  }
167
167
  const loadConfigFile = (() => {
168
- const loadYAML = async function loadYAML(filepath) {
169
- const content = autoDecode(await fs.readFile(filepath));
170
- return yaml.parse(content, YAML_OPTIONS);
171
- };
172
- const explorer = cosmiconfig(APP.NAME, {
173
- cache: false,
174
- stopDir: getHomedir(),
175
- searchPlaces: CONFIG_SEARCH_PLACES,
176
- loaders: {
177
- ...defaultLoaders,
178
- ".json": loadYAML,
179
- ".yaml": loadYAML,
180
- ".yml": loadYAML,
181
- noExt: loadYAML
168
+ const jsReg = /\.[cm]?js$/;
169
+ const filenames = [
170
+ "package.json",
171
+ ...getNodeSearchPlaces(COMMAND_NAMES),
172
+ ...PY_YAMLLINT_CONFIG_FILES
173
+ ];
174
+ const loadFile = async (filepath, throwOnFailure = false) => {
175
+ try {
176
+ filepath = path.resolve(filepath);
177
+ const filename = path.basename(filepath);
178
+ if (jsReg.test(filepath) || filepath.endsWith(".ts")) {
179
+ const jiti = createJiti(import.meta.url);
180
+ if (await fs.stat(filepath).then((x) => x.size).catch(() => 0) > 0) {
181
+ const mod = await jiti.import(filepath, { default: true });
182
+ const value = mod.default ?? mod;
183
+ if (typeof value === "object" && value !== null) return value;
184
+ }
185
+ } else if (filename === "package.json") {
186
+ const content = autoDecode(await fs.readFile(filepath));
187
+ const pkg = JSON.parse(content);
188
+ if (typeof pkg !== "object" || pkg === null) return;
189
+ for (const name of COMMAND_NAMES) {
190
+ const value = pkg[name];
191
+ if (value) return value;
192
+ }
193
+ } else {
194
+ const content = autoDecode(await fs.readFile(filepath));
195
+ return yaml.parse(content, YAML_OPTIONS);
196
+ }
197
+ throw new Error();
198
+ } catch {
199
+ if (throwOnFailure) throw new YamlLintConfigError(`failed to load config file "${filepath}"`);
182
200
  }
183
- });
184
- return function loadConfigFile(filepath) {
185
- return filepath === void 0 ? explorer.search() : explorer.load(filepath);
201
+ };
202
+ return async function loadConfigFile(filepath) {
203
+ if (typeof filepath === "string") return loadFile(filepath, true);
204
+ const startDir = filepath?.startDir ?? process.cwd();
205
+ const stopDir = filepath?.stopDir === void 0 ? getHomedir() : path.resolve(filepath.stopDir);
206
+ let currDir = path.resolve(startDir);
207
+ do {
208
+ for (const filename of filenames) {
209
+ const curr = path.join(currDir, filename);
210
+ if (await fs.stat(curr).then((x) => x.isFile() || x.isSymbolicLink()).catch(() => false)) {
211
+ const content = await loadFile(curr);
212
+ if (content) return content;
213
+ }
214
+ }
215
+ currDir = path.dirname(currDir);
216
+ } while (currDir !== stopDir && currDir !== path.dirname(currDir));
186
217
  };
187
218
  })();
188
219
  async function detectUserGlobalConfig() {
@@ -192,11 +223,11 @@ async function detectUserGlobalConfig() {
192
223
  else userGlobalConfig = path.join(getHomedir(), ".config", "yamllint", "config");
193
224
  return await fs.stat(userGlobalConfig).then((x) => x.isFile()).catch(() => false) ? userGlobalConfig : void 0;
194
225
  }
195
- async function loadYamlLintConfig() {
226
+ async function loadYamlLintConfig(options) {
196
227
  let userGlobalConfig;
197
228
  let load;
198
229
  let conf;
199
- if (load = await loadConfigFile()) conf = await YamlLintConfig.init({ _data: load.config });
230
+ if (load = await loadConfigFile(options)) conf = await YamlLintConfig.init({ _data: load });
200
231
  else if (userGlobalConfig = await detectUserGlobalConfig()) conf = await YamlLintConfig.init({ file: userGlobalConfig });
201
232
  else conf = await YamlLintConfig.init({ content: "extends: default" });
202
233
  return conf;
@@ -1,5 +1,5 @@
1
- import { description, name, version } from "./package.mjs";
2
- import { getDefaultSearchPlaces } from "cosmiconfig";
1
+ import { bin, description, name, version } from "./package.mjs";
2
+ const COMMAND_NAMES = Object.keys(bin);
3
3
  const APP = {
4
4
  NAME: name,
5
5
  VERSION: version,
@@ -10,17 +10,15 @@ const APP = {
10
10
  "such as lines length, trailing spaces, indentation, etc."
11
11
  ].join(" ")
12
12
  };
13
- const YAML_OPTIONS = {
14
- version: "1.1",
15
- uniqueKeys: false
16
- };
17
- const CONFIG_SEARCH_PLACES = [
18
- ...getDefaultSearchPlaces(APP.NAME).filter((x) => !x.includes(`${APP.NAME}rc`)),
19
- ...getDefaultSearchPlaces("yamllint").filter((x) => !x.includes("yamllintrc")),
13
+ const PY_YAMLLINT_CONFIG_FILES = [
20
14
  ".yamllint",
21
15
  ".yamllint.yaml",
22
16
  ".yamllint.yml"
23
17
  ];
18
+ const YAML_OPTIONS = {
19
+ version: "1.1",
20
+ uniqueKeys: false
21
+ };
24
22
  const LEVELS = [
25
23
  null,
26
24
  "warning",
@@ -40,4 +38,4 @@ const PROBLEM_LEVELS = {
40
38
  };
41
39
  const PY_EOL = /\r\n|\r|\n|\v|\f|\x1c|\x1d|\x1e|\x85|\u2028|\u2029/;
42
40
  const PY_EOL_END = new RegExp(`(${PY_EOL.source})$`);
43
- export { ALIASES, APP, CONFIG_SEARCH_PLACES, LEVELS, PROBLEM_LEVELS, PY_EOL, PY_EOL_END, YAML_OPTIONS };
41
+ export { ALIASES, APP, COMMAND_NAMES, LEVELS, PROBLEM_LEVELS, PY_EOL, PY_EOL_END, PY_YAMLLINT_CONFIG_FILES, YAML_OPTIONS };
package/dist/package.mjs CHANGED
@@ -1,4 +1,8 @@
1
1
  var name = "yamllint-js";
2
2
  var description = "A linter for YAML files β€” an unofficial native Node.js port of Python yamllint.";
3
- var version = "0.2.1";
4
- export { description, name, version };
3
+ var version = "0.2.3";
4
+ var bin = {
5
+ "yamllint-js": "dist/main.mjs",
6
+ "yamllint": "dist/main.mjs"
7
+ };
8
+ export { bin, description, name, version };
package/dist/utils.mjs CHANGED
@@ -49,4 +49,14 @@ const toKebabCaseKeys = (data) => {
49
49
  for (const key in data) newData[toKebabCase(key)] = data[key];
50
50
  return newData;
51
51
  };
52
- export { B, bufferStartsWith, formatErrorMessage, getHomedir, once, splitlines, toKebabCaseKeys };
52
+ const getNodeSearchPlaces = (name, set = /* @__PURE__ */ new Set()) => {
53
+ const names = Array.isArray(name) ? name : [name];
54
+ for (const n of names) {
55
+ set.add(`${n}.config.js`);
56
+ set.add(`${n}.config.ts`);
57
+ set.add(`${n}.config.cjs`);
58
+ set.add(`${n}.config.mjs`);
59
+ }
60
+ return set;
61
+ };
62
+ export { B, bufferStartsWith, formatErrorMessage, getHomedir, getNodeSearchPlaces, once, splitlines, toKebabCaseKeys };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "yamllint-js",
3
3
  "description": "A linter for YAML files β€” an unofficial native Node.js port of Python yamllint.",
4
- "version": "0.2.1",
4
+ "version": "0.2.3",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
7
7
  "author": {
@@ -23,8 +23,10 @@
23
23
  "lint:eslint": "eslint .",
24
24
  "lint:types": "tsc --noEmit",
25
25
  "lint:markdown": "markdownlint-cli2",
26
- "lint:yaml": "node dist/main.mjs -c yamllint.self.config.js . 2> /dev/null || tsx src/main.ts -c yamllint.self.config.js .",
27
- "build": "tsdown"
26
+ "lint:yaml": "node dist/main.mjs -c yamllint.self.config.js .",
27
+ "prelint:yaml": "npm run build:nodts",
28
+ "build": "tsdown",
29
+ "build:nodts": "tsdown --no-dts"
28
30
  },
29
31
  "files": [
30
32
  "dist",
@@ -51,9 +53,9 @@
51
53
  "./internal": "./dist/internal.mjs"
52
54
  },
53
55
  "dependencies": {
54
- "cosmiconfig": "^9.0.0",
55
56
  "iconv-lite": "^0.7.2",
56
57
  "ignore": "^7.0.5",
58
+ "jiti": "^2.6.1",
57
59
  "recheck": "^4.5.0",
58
60
  "yaml": "^2.8.2",
59
61
  "yargs": "^18.0.0",
@@ -67,11 +69,9 @@
67
69
  "@vitest/coverage-v8": "^4.0.18",
68
70
  "@vitest/ui": "^4.0.18",
69
71
  "eslint": "^9.39.2",
70
- "jiti": "^2.6.1",
71
72
  "markdownlint-cli2": "^0.20.0",
72
73
  "standard-version": "^9.5.0",
73
74
  "tsdown": "^0.20.1",
74
- "tsx": "^4.21.0",
75
75
  "typescript": "^5.9.3",
76
76
  "typescript-eslint": "^8.54.0",
77
77
  "vitest": "^4.0.18"