lfify 1.2.0 → 1.2.1

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.
@@ -22,7 +22,7 @@ jobs:
22
22
  - name: Setup Node.js
23
23
  uses: actions/setup-node@v6
24
24
  with:
25
- node-version: "24"
25
+ node-version: '24'
26
26
  - name: Install dependencies
27
27
  run: npm clean-install
28
28
  - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
@@ -2,41 +2,41 @@ name: Lint and Test
2
2
 
3
3
  on:
4
4
  pull_request:
5
- branches: [ main ]
5
+ branches: [main]
6
6
  push:
7
- branches: [ main ]
7
+ branches: [main]
8
8
 
9
9
  jobs:
10
10
  lint:
11
11
  runs-on: ubuntu-latest
12
12
 
13
13
  steps:
14
- - uses: actions/checkout@v3
15
-
16
- - name: Setup Node.js
17
- uses: actions/setup-node@v3
18
- with:
19
- node-version: '18'
20
-
21
- - name: Install dependencies
22
- run: npm ci
23
-
24
- - name: Run linting
25
- run: npm run lint || true
14
+ - uses: actions/checkout@v3
15
+
16
+ - name: Setup Node.js
17
+ uses: actions/setup-node@v3
18
+ with:
19
+ node-version: '18'
20
+
21
+ - name: Install dependencies
22
+ run: npm ci
23
+
24
+ - name: Run linting
25
+ run: npm run lint || true
26
26
 
27
27
  test:
28
28
  runs-on: ubuntu-latest
29
29
 
30
30
  steps:
31
- - uses: actions/checkout@v3
32
-
33
- - name: Setup Node.js
34
- uses: actions/setup-node@v3
35
- with:
36
- node-version: '18'
37
-
38
- - name: Install dependencies
39
- run: npm ci
40
-
41
- - name: Run tests
42
- run: npm test
31
+ - uses: actions/checkout@v3
32
+
33
+ - name: Setup Node.js
34
+ uses: actions/setup-node@v3
35
+ with:
36
+ node-version: '18'
37
+
38
+ - name: Install dependencies
39
+ run: npm ci
40
+
41
+ - name: Run tests
42
+ run: npm test
@@ -14,4 +14,4 @@
14
14
  "build/**",
15
15
  "coverage/**"
16
16
  ]
17
- }
17
+ }
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ __fixtures__/
4
+ package-lock.json
5
+ CHANGELOG.md
package/.prettierrc ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": true,
4
+ "trailingComma": "all",
5
+ "printWidth": 80,
6
+ "tabWidth": 2,
7
+ "useTabs": false,
8
+ "endOfLine": "lf"
9
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
3
+ }
@@ -22,10 +22,8 @@
22
22
  "type": "node",
23
23
  "request": "launch",
24
24
  "name": "Launch Program",
25
- "skipFiles": [
26
- "<node_internals>/**"
27
- ],
25
+ "skipFiles": ["<node_internals>/**"],
28
26
  "program": "${workspaceFolder}/index.cjs"
29
27
  }
30
28
  ]
31
- }
29
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
3
+ "editor.formatOnSave": true,
4
+ "editor.codeActionsOnSave": {
5
+ "source.fixAll.eslint": "explicit"
6
+ },
7
+ "[javascript]": {
8
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
9
+ },
10
+ "[json]": {
11
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
12
+ },
13
+ "[markdown]": {
14
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
15
+ }
16
+ }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [1.2.1](https://github.com/GyeongHoKim/lfify/compare/v1.2.0...v1.2.1) (2026-03-18)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * unlink tmp files when rename failed ([173a38f](https://github.com/GyeongHoKim/lfify/commit/173a38f026d2f37dc521a4a5e089d071cfd425c9))
7
+
1
8
  # [1.2.0](https://github.com/GyeongHoKim/lfify/compare/v1.1.0...v1.2.0) (2026-03-16)
2
9
 
3
10
 
package/README.md CHANGED
@@ -42,12 +42,12 @@ npx lfify
42
42
 
43
43
  ## Options
44
44
 
45
- | Option | Description |
46
- | -------------------- | --------------------------------------------------------------------------- |
47
- | `--config <path>` | Specify a custom path for the configuration file. Default is `.lfifyrc.json`. |
48
- | `--entry <path>` | Specify the entry directory to process. Default is `./`. |
49
- | `--include <pattern>`| Glob pattern(s) to include. Can be used multiple times. |
50
- | `--exclude <pattern>`| Glob pattern(s) to exclude. Can be used multiple times. |
45
+ | Option | Description |
46
+ | --------------------- | ----------------------------------------------------------------------------- |
47
+ | `--config <path>` | Specify a custom path for the configuration file. Default is `.lfifyrc.json`. |
48
+ | `--entry <path>` | Specify the entry directory to process. Default is `./`. |
49
+ | `--include <pattern>` | Glob pattern(s) to include. Can be used multiple times. |
50
+ | `--exclude <pattern>` | Glob pattern(s) to exclude. Can be used multiple times. |
51
51
 
52
52
  ## Examples
53
53
 
@@ -68,12 +68,14 @@ npx lfify --config ./custom-config.json
68
68
  ## Default behavior
69
69
 
70
70
  When no config file is found and no CLI options are provided, lfify uses sensible defaults:
71
+
71
72
  - **include**: `**/*` (all files)
72
73
  - **exclude**: `node_modules/**`, `.git/**`, `dist/**`, `build/**`, `coverage/**`
73
74
 
74
75
  ## Priority
75
76
 
76
77
  CLI options take precedence over config file values:
78
+
77
79
  1. CLI arguments (highest)
78
80
  2. Config file
79
81
  3. Default values (lowest)
package/__mocks__/path.js CHANGED
@@ -14,4 +14,4 @@ path.relative = jest.fn().mockImplementation((from, to) => {
14
14
  return actualPath.relative(from, to);
15
15
  });
16
16
 
17
- module.exports = path;
17
+ module.exports = path;
package/eslint.config.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import globals from "globals";
2
- import pluginJs from "@eslint/js";
3
-
1
+ import globals from 'globals';
2
+ import pluginJs from '@eslint/js';
3
+ import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
4
4
 
5
5
  /** @type {import('eslint').Linter.Config[]} */
6
6
  export default [
7
- { ignores: ["**/__fixtures__/**"] },
8
- { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } },
7
+ { ignores: ['**/__fixtures__/**'] },
8
+ { files: ['**/*.js'], languageOptions: { sourceType: 'commonjs' } },
9
9
  {
10
10
  languageOptions: {
11
11
  globals: {
@@ -15,4 +15,5 @@ export default [
15
15
  },
16
16
  },
17
17
  pluginJs.configs.recommended,
18
+ eslintPluginPrettierRecommended,
18
19
  ];
package/index.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { readFile, readdir, rename } = require("fs/promises");
4
- const { createReadStream, createWriteStream } = require("fs");
5
- const { resolve, join, relative } = require("path");
6
- const { isMatch } = require("micromatch");
7
- const { Transform } = require("stream");
8
- const { pipeline } = require("stream/promises");
3
+ const { readFile, readdir, rename, unlink } = require('fs/promises');
4
+ const { createReadStream, createWriteStream } = require('fs');
5
+ const { resolve, join, relative } = require('path');
6
+ const { isMatch } = require('micromatch');
7
+ const { Transform } = require('stream');
8
+ const { pipeline } = require('stream/promises');
9
9
 
10
10
  /** @type {ReadonlyArray<string>} */
11
11
  const LOG_LEVELS = ['error', 'warn', 'info'];
@@ -43,7 +43,7 @@ const DEFAULT_CONFIG = {
43
43
  entry: './',
44
44
  include: [],
45
45
  exclude: [],
46
- logLevel: 'error'
46
+ logLevel: 'error',
47
47
  };
48
48
 
49
49
  /**
@@ -53,14 +53,8 @@ const DEFAULT_CONFIG = {
53
53
  const SENSIBLE_DEFAULTS = {
54
54
  entry: './',
55
55
  include: ['**/*'],
56
- exclude: [
57
- 'node_modules/**',
58
- '.git/**',
59
- 'dist/**',
60
- 'build/**',
61
- 'coverage/**'
62
- ],
63
- logLevel: 'error'
56
+ exclude: ['node_modules/**', '.git/**', 'dist/**', 'build/**', 'coverage/**'],
57
+ logLevel: 'error',
64
58
  };
65
59
 
66
60
  /**
@@ -69,8 +63,14 @@ const SENSIBLE_DEFAULTS = {
69
63
  */
70
64
  const CONFIG_SCHEMA = {
71
65
  entry: (value) => typeof value === 'string',
72
- include: (value) => Array.isArray(value) && value.length > 0 && value.every(item => typeof item === 'string'),
73
- exclude: (value) => Array.isArray(value) && value.length > 0 && value.every(item => typeof item === 'string'),
66
+ include: (value) =>
67
+ Array.isArray(value) &&
68
+ value.length > 0 &&
69
+ value.every((item) => typeof item === 'string'),
70
+ exclude: (value) =>
71
+ Array.isArray(value) &&
72
+ value.length > 0 &&
73
+ value.every((item) => typeof item === 'string'),
74
74
  logLevel: (value) => LOG_LEVELS.includes(value),
75
75
  };
76
76
 
@@ -129,13 +129,16 @@ async function readConfig(configPath) {
129
129
  return {
130
130
  ...DEFAULT_CONFIG,
131
131
  ...config,
132
- entry: resolve(process.cwd(), config.entry || DEFAULT_CONFIG.entry)
132
+ entry: resolve(process.cwd(), config.entry || DEFAULT_CONFIG.entry),
133
133
  };
134
134
  } catch (err) {
135
135
  if (err.code === 'ENOENT') {
136
136
  logger.error(`Configuration file not found: ${configPath}`, configPath);
137
137
  } else {
138
- logger.error(`Error reading configuration file: ${err.message}`, configPath);
138
+ logger.error(
139
+ `Error reading configuration file: ${err.message}`,
140
+ configPath,
141
+ );
139
142
  }
140
143
 
141
144
  if (require.main === module) {
@@ -168,7 +171,10 @@ async function resolveConfig(cliOptions) {
168
171
  } catch (err) {
169
172
  if (err.code !== 'ENOENT') {
170
173
  // Re-throw parsing/validation errors
171
- logger.error(`Error reading configuration file: ${err.message}`, cliOptions.configPath);
174
+ logger.error(
175
+ `Error reading configuration file: ${err.message}`,
176
+ cliOptions.configPath,
177
+ );
172
178
  throw err;
173
179
  }
174
180
  // ENOENT is okay - config file is optional now
@@ -176,16 +182,29 @@ async function resolveConfig(cliOptions) {
176
182
  }
177
183
 
178
184
  // Determine final values with precedence: CLI > config file > defaults
179
- const hasCLIInclude = Array.isArray(cliOptions.include) && cliOptions.include.length > 0;
180
- const hasCLIExclude = Array.isArray(cliOptions.exclude) && cliOptions.exclude.length > 0;
185
+ const hasCLIInclude =
186
+ Array.isArray(cliOptions.include) && cliOptions.include.length > 0;
187
+ const hasCLIExclude =
188
+ Array.isArray(cliOptions.exclude) && cliOptions.exclude.length > 0;
181
189
  const hasCLIEntry = typeof cliOptions.entry === 'string';
182
- const hasCLILogLevel = typeof cliOptions.logLevel === 'string' && LOG_LEVELS.includes(cliOptions.logLevel);
190
+ const hasCLILogLevel =
191
+ typeof cliOptions.logLevel === 'string' &&
192
+ LOG_LEVELS.includes(cliOptions.logLevel);
183
193
 
184
194
  const hasFileConfig = fileConfig !== null;
185
- const hasFileInclude = hasFileConfig && Array.isArray(fileConfig.include) && fileConfig.include.length > 0;
186
- const hasFileExclude = hasFileConfig && Array.isArray(fileConfig.exclude) && fileConfig.exclude.length > 0;
195
+ const hasFileInclude =
196
+ hasFileConfig &&
197
+ Array.isArray(fileConfig.include) &&
198
+ fileConfig.include.length > 0;
199
+ const hasFileExclude =
200
+ hasFileConfig &&
201
+ Array.isArray(fileConfig.exclude) &&
202
+ fileConfig.exclude.length > 0;
187
203
  const hasFileEntry = hasFileConfig && typeof fileConfig.entry === 'string';
188
- const hasFileLogLevel = hasFileConfig && fileConfig.logLevel && LOG_LEVELS.includes(fileConfig.logLevel);
204
+ const hasFileLogLevel =
205
+ hasFileConfig &&
206
+ fileConfig.logLevel &&
207
+ LOG_LEVELS.includes(fileConfig.logLevel);
189
208
 
190
209
  // Resolve each config property
191
210
  let include, exclude, entry, logLevel;
@@ -230,7 +249,7 @@ async function resolveConfig(cliOptions) {
230
249
  entry: resolve(process.cwd(), entry),
231
250
  include,
232
251
  exclude,
233
- logLevel
252
+ logLevel,
234
253
  };
235
254
  }
236
255
 
@@ -241,7 +260,7 @@ async function resolveConfig(cliOptions) {
241
260
  function parseArgs() {
242
261
  const args = process.argv.slice(2);
243
262
  const options = {
244
- configPath: '.lfifyrc.json'
263
+ configPath: '.lfifyrc.json',
245
264
  };
246
265
 
247
266
  for (let i = 0; i < args.length; i++) {
@@ -318,18 +337,23 @@ async function convertCRLFtoLF(dirPath, config) {
318
337
  /**
319
338
  * @todo Node.js is single-threaded, if I want to convert files in parallel, I need to use worker_threads
320
339
  */
321
- await Promise.all(entries.map(async entry => {
322
- const fullPath = join(dirPath, entry.name);
323
- const relativePath = relative(process.cwd(), fullPath).replace(/\\/g, "/");
324
-
325
- if (entry.isDirectory()) {
326
- await convertCRLFtoLF(fullPath, config);
327
- } else if (entry.isFile() && shouldProcessFile(relativePath, config)) {
328
- await processFile(fullPath);
329
- } else {
330
- logger.info(`skipped: ${relativePath}`, fullPath);
331
- }
332
- }));
340
+ await Promise.all(
341
+ entries.map(async (entry) => {
342
+ const fullPath = join(dirPath, entry.name);
343
+ const relativePath = relative(process.cwd(), fullPath).replace(
344
+ /\\/g,
345
+ '/',
346
+ );
347
+
348
+ if (entry.isDirectory()) {
349
+ await convertCRLFtoLF(fullPath, config);
350
+ } else if (entry.isFile() && shouldProcessFile(relativePath, config)) {
351
+ await processFile(fullPath);
352
+ } else {
353
+ logger.info(`skipped: ${relativePath}`, fullPath);
354
+ }
355
+ }),
356
+ );
333
357
  } catch (err) {
334
358
  logger.error(`error reading directory: ${dirPath}`, dirPath, err);
335
359
  throw err;
@@ -356,13 +380,13 @@ async function processFile(filePath) {
356
380
  },
357
381
  flush(callback) {
358
382
  callback(null, this._leftover ?? '');
359
- }
383
+ },
360
384
  });
361
385
  try {
362
386
  await pipeline(
363
387
  createReadStream(filePath, { encoding: 'utf8' }),
364
388
  crlf2lf,
365
- createWriteStream(tmpPath, { encoding: 'utf8' })
389
+ createWriteStream(tmpPath, { encoding: 'utf8' }),
366
390
  );
367
391
  logger.info(`converted ${filePath}`);
368
392
  } catch (err) {
@@ -373,6 +397,7 @@ async function processFile(filePath) {
373
397
  await rename(tmpPath, filePath);
374
398
  } catch (err) {
375
399
  logger.error(`error rename file: ${tmpPath} to ${filePath}`);
400
+ unlink(tmpPath);
376
401
  throw err;
377
402
  }
378
403
  }
@@ -387,7 +412,7 @@ async function main() {
387
412
 
388
413
  await convertCRLFtoLF(config.entry, config);
389
414
 
390
- logger.info("conversion completed.", config.entry);
415
+ logger.info('conversion completed.', config.entry);
391
416
  }
392
417
 
393
418
  if (require.main === module) {
package/index.e2e.test.js CHANGED
@@ -49,7 +49,10 @@ describe('E2E: CRLF to LF with real filesystem', () => {
49
49
  it('converts files under entry and excludes node_modules and .git', async () => {
50
50
  await copyDir(path.join(FIXTURES_DIR, 'default-sensible'), tempDir);
51
51
  await fs.rename(path.join(tempDir, '_git'), path.join(tempDir, '.git'));
52
- await fs.rename(path.join(tempDir, '_node_modules'), path.join(tempDir, 'node_modules'));
52
+ await fs.rename(
53
+ path.join(tempDir, '_node_modules'),
54
+ path.join(tempDir, 'node_modules'),
55
+ );
53
56
  process.chdir(tempDir);
54
57
 
55
58
  const config = await resolveConfig({});
@@ -57,14 +60,20 @@ describe('E2E: CRLF to LF with real filesystem', () => {
57
60
 
58
61
  const appJs = await fs.readFile(path.join(tempDir, 'src', 'app.js'));
59
62
  expect(appJs.includes(CRLF)).toBe(false);
60
- expect(appJs.equals(Buffer.from('console.log("app");\n', 'utf8'))).toBe(true);
63
+ expect(appJs.equals(Buffer.from('console.log("app");\n', 'utf8'))).toBe(
64
+ true,
65
+ );
61
66
 
62
- const readmeTxt = await fs.readFile(path.join(tempDir, 'src', 'readme.txt'));
67
+ const readmeTxt = await fs.readFile(
68
+ path.join(tempDir, 'src', 'readme.txt'),
69
+ );
63
70
  expect(readmeTxt.includes(CRLF)).toBe(false);
64
- expect(readmeTxt.equals(Buffer.from('hello\nworld\n', 'utf8'))).toBe(true);
71
+ expect(readmeTxt.equals(Buffer.from('hello\nworld\n', 'utf8'))).toBe(
72
+ true,
73
+ );
65
74
 
66
75
  const nodeModulesPkg = await fs.readFile(
67
- path.join(tempDir, 'node_modules', 'pkg', 'index.js')
76
+ path.join(tempDir, 'node_modules', 'pkg', 'index.js'),
68
77
  );
69
78
  expect(nodeModulesPkg.includes(CRLF)).toBe(true);
70
79
 
@@ -85,7 +94,9 @@ describe('E2E: CRLF to LF with real filesystem', () => {
85
94
  expect(mainJs.includes(CRLF)).toBe(false);
86
95
  expect(mainJs.equals(Buffer.from('const x = 1;\n', 'utf8'))).toBe(true);
87
96
 
88
- const skipOtherJs = await fs.readFile(path.join(tempDir, 'skip', 'other.js'));
97
+ const skipOtherJs = await fs.readFile(
98
+ path.join(tempDir, 'skip', 'other.js'),
99
+ );
89
100
  expect(skipOtherJs.includes(CRLF)).toBe(true);
90
101
 
91
102
  const docTxt = await fs.readFile(path.join(tempDir, 'doc.txt'));
@@ -100,7 +111,7 @@ describe('E2E: CRLF to LF with real filesystem', () => {
100
111
 
101
112
  const config = await resolveConfig({
102
113
  configPath: '.lfifyrc.json',
103
- include: ['**/*.js']
114
+ include: ['**/*.js'],
104
115
  });
105
116
  await convertCRLFtoLF(config.entry, config);
106
117
 
package/index.test.js CHANGED
@@ -1,5 +1,12 @@
1
1
  const mock = require('mock-fs');
2
- const { readConfig, parseArgs, processFile, resolveConfig, shouldProcessFile, SENSIBLE_DEFAULTS } = require('./index.cjs');
2
+ const {
3
+ readConfig,
4
+ parseArgs,
5
+ processFile,
6
+ resolveConfig,
7
+ shouldProcessFile,
8
+ SENSIBLE_DEFAULTS,
9
+ } = require('./index.cjs');
3
10
  const fs = require('fs');
4
11
 
5
12
  function baseMock(overrides = {}) {
@@ -13,7 +20,7 @@ function baseMock(overrides = {}) {
13
20
  'node_modules/file.js': 'console.log("test");\r\n',
14
21
  'node_modules/subdir/file4.txt': 'test\r\n',
15
22
  'index.js': 'console.log("test");\r\n',
16
- ...overrides
23
+ ...overrides,
17
24
  };
18
25
  }
19
26
 
@@ -35,17 +42,19 @@ describe('CRLF to LF Converter', () => {
35
42
  const validConfig = {
36
43
  entry: './',
37
44
  include: ['*.js'],
38
- exclude: ['node_modules/**']
45
+ exclude: ['node_modules/**'],
39
46
  };
40
47
  mock(baseMock({ '.lfifyrc.json': JSON.stringify(validConfig) }));
41
48
 
42
49
  const config = await readConfig('.lfifyrc.json');
43
50
 
44
- expect(config).toEqual(expect.objectContaining({
45
- entry: expect.any(String),
46
- include: expect.any(Array),
47
- exclude: expect.any(Array)
48
- }));
51
+ expect(config).toEqual(
52
+ expect.objectContaining({
53
+ entry: expect.any(String),
54
+ include: expect.any(Array),
55
+ exclude: expect.any(Array),
56
+ }),
57
+ );
49
58
  });
50
59
 
51
60
  it('should throw error when config file is not found', async () => {
@@ -61,7 +70,12 @@ describe('CRLF to LF Converter', () => {
61
70
 
62
71
  describe('parseArgs', () => {
63
72
  it('should return config path when --config option is provided', () => {
64
- process.argv = ['node', 'lfify', '--config', './path/for/test/.lfifyrc.json'];
73
+ process.argv = [
74
+ 'node',
75
+ 'lfify',
76
+ '--config',
77
+ './path/for/test/.lfifyrc.json',
78
+ ];
65
79
 
66
80
  const options = parseArgs();
67
81
 
@@ -83,7 +97,14 @@ describe('CRLF to LF Converter', () => {
83
97
  });
84
98
 
85
99
  it('should return multiple include patterns when multiple --include options are provided', () => {
86
- process.argv = ['node', 'lfify', '--include', '**/*.js', '--include', '**/*.ts'];
100
+ process.argv = [
101
+ 'node',
102
+ 'lfify',
103
+ '--include',
104
+ '**/*.js',
105
+ '--include',
106
+ '**/*.ts',
107
+ ];
87
108
  const options = parseArgs();
88
109
  expect(options.include).toEqual(['**/*.js', '**/*.ts']);
89
110
  });
@@ -95,7 +116,14 @@ describe('CRLF to LF Converter', () => {
95
116
  });
96
117
 
97
118
  it('should return multiple exclude patterns when multiple --exclude options are provided', () => {
98
- process.argv = ['node', 'lfify', '--exclude', 'dist/**', '--exclude', 'coverage/**'];
119
+ process.argv = [
120
+ 'node',
121
+ 'lfify',
122
+ '--exclude',
123
+ 'dist/**',
124
+ '--exclude',
125
+ 'coverage/**',
126
+ ];
99
127
  const options = parseArgs();
100
128
  expect(options.exclude).toEqual(['dist/**', 'coverage/**']);
101
129
  });
@@ -107,7 +135,20 @@ describe('CRLF to LF Converter', () => {
107
135
  });
108
136
 
109
137
  it('should handle all options together', () => {
110
- process.argv = ['node', 'lfify', '--config', 'custom.json', '--include', '*.js', '--exclude', 'dist/**', '--entry', './lib', '--log-level', 'info'];
138
+ process.argv = [
139
+ 'node',
140
+ 'lfify',
141
+ '--config',
142
+ 'custom.json',
143
+ '--include',
144
+ '*.js',
145
+ '--exclude',
146
+ 'dist/**',
147
+ '--entry',
148
+ './lib',
149
+ '--log-level',
150
+ 'info',
151
+ ];
111
152
  const options = parseArgs();
112
153
  expect(options.configPath).toBe('custom.json');
113
154
  expect(options.include).toEqual(['*.js']);
@@ -146,7 +187,9 @@ describe('CRLF to LF Converter', () => {
146
187
 
147
188
  it('should return false when file matches exclude pattern', () => {
148
189
  const config = { include: ['**/*.js'], exclude: ['node_modules/**'] };
149
- expect(shouldProcessFile('node_modules/pkg/index.js', config)).toBe(false);
190
+ expect(shouldProcessFile('node_modules/pkg/index.js', config)).toBe(
191
+ false,
192
+ );
150
193
  });
151
194
 
152
195
  it('should return false when file does not match include pattern', () => {
@@ -155,13 +198,19 @@ describe('CRLF to LF Converter', () => {
155
198
  });
156
199
 
157
200
  it('should handle multiple include patterns', () => {
158
- const config = { include: ['**/*.js', '**/*.ts'], exclude: ['node_modules/**'] };
201
+ const config = {
202
+ include: ['**/*.js', '**/*.ts'],
203
+ exclude: ['node_modules/**'],
204
+ };
159
205
  expect(shouldProcessFile('src/app.js', config)).toBe(true);
160
206
  expect(shouldProcessFile('src/app.ts', config)).toBe(true);
161
207
  });
162
208
 
163
209
  it('should handle multiple exclude patterns', () => {
164
- const config = { include: ['**/*.js'], exclude: ['node_modules/**', 'dist/**', 'build/**', 'coverage/**'] };
210
+ const config = {
211
+ include: ['**/*.js'],
212
+ exclude: ['node_modules/**', 'dist/**', 'build/**', 'coverage/**'],
213
+ };
165
214
  expect(shouldProcessFile('src/file.js', config)).toBe(true);
166
215
  expect(shouldProcessFile('node_modules/pkg/file.js', config)).toBe(false);
167
216
  expect(shouldProcessFile('dist/bundle.js', config)).toBe(false);
@@ -194,7 +243,7 @@ describe('CRLF to LF Converter', () => {
194
243
  const options = {
195
244
  include: ['**/*.js'],
196
245
  exclude: ['node_modules/**'],
197
- entry: './src'
246
+ entry: './src',
198
247
  };
199
248
  const config = await resolveConfig(options);
200
249
 
@@ -211,17 +260,19 @@ describe('CRLF to LF Converter', () => {
211
260
  });
212
261
 
213
262
  it('should override config file values with CLI options', async () => {
214
- mock(baseMock({
215
- '.lfifyrc.json': JSON.stringify({
216
- entry: './',
217
- include: ['**/*.md'],
218
- exclude: ['dist/**']
219
- })
220
- }));
263
+ mock(
264
+ baseMock({
265
+ '.lfifyrc.json': JSON.stringify({
266
+ entry: './',
267
+ include: ['**/*.md'],
268
+ exclude: ['dist/**'],
269
+ }),
270
+ }),
271
+ );
221
272
 
222
273
  const options = {
223
274
  configPath: '.lfifyrc.json',
224
- include: ['**/*.js']
275
+ include: ['**/*.js'],
225
276
  };
226
277
  const config = await resolveConfig(options);
227
278
 
@@ -230,13 +281,15 @@ describe('CRLF to LF Converter', () => {
230
281
  });
231
282
 
232
283
  it('should load config file when configPath is provided and file exists', async () => {
233
- mock(baseMock({
234
- '.lfifyrc.json': JSON.stringify({
235
- entry: './lib',
236
- include: ['**/*.ts'],
237
- exclude: ['test/**']
238
- })
239
- }));
284
+ mock(
285
+ baseMock({
286
+ '.lfifyrc.json': JSON.stringify({
287
+ entry: './lib',
288
+ include: ['**/*.ts'],
289
+ exclude: ['test/**'],
290
+ }),
291
+ }),
292
+ );
240
293
 
241
294
  const options = { configPath: '.lfifyrc.json' };
242
295
  const config = await resolveConfig(options);
@@ -275,30 +328,34 @@ describe('CRLF to LF Converter', () => {
275
328
  });
276
329
 
277
330
  it('should use logLevel from config file when provided', async () => {
278
- mock(baseMock({
279
- '.lfifyrc.json': JSON.stringify({
280
- entry: './',
281
- include: ['**/*.js'],
282
- exclude: ['node_modules/**'],
283
- logLevel: 'info'
284
- })
285
- }));
331
+ mock(
332
+ baseMock({
333
+ '.lfifyrc.json': JSON.stringify({
334
+ entry: './',
335
+ include: ['**/*.js'],
336
+ exclude: ['node_modules/**'],
337
+ logLevel: 'info',
338
+ }),
339
+ }),
340
+ );
286
341
  const config = await resolveConfig({ configPath: '.lfifyrc.json' });
287
342
  expect(config.logLevel).toBe('info');
288
343
  });
289
344
 
290
345
  it('should override config file logLevel with CLI --log-level', async () => {
291
- mock(baseMock({
292
- '.lfifyrc.json': JSON.stringify({
293
- entry: './',
294
- include: ['**/*.js'],
295
- exclude: ['node_modules/**'],
296
- logLevel: 'warn'
297
- })
298
- }));
346
+ mock(
347
+ baseMock({
348
+ '.lfifyrc.json': JSON.stringify({
349
+ entry: './',
350
+ include: ['**/*.js'],
351
+ exclude: ['node_modules/**'],
352
+ logLevel: 'warn',
353
+ }),
354
+ }),
355
+ );
299
356
  const config = await resolveConfig({
300
357
  configPath: '.lfifyrc.json',
301
- logLevel: 'info'
358
+ logLevel: 'info',
302
359
  });
303
360
  expect(config.logLevel).toBe('info');
304
361
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lfify",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "private": false,
5
5
  "description": "make your crlf to lf",
6
6
  "main": "index.cjs",
@@ -12,7 +12,9 @@
12
12
  "test": "npm run test:unit && npm run test:e2e",
13
13
  "test:unit": "jest --testPathPattern=\"index\\.test\\.js\"",
14
14
  "test:e2e": "jest --testPathPattern=\"index\\.e2e\\.test\\.js\"",
15
- "lint": "eslint ."
15
+ "lint": "eslint .",
16
+ "format": "prettier --write .",
17
+ "format:check": "prettier --check ."
16
18
  },
17
19
  "repository": {
18
20
  "type": "git",
@@ -45,9 +47,12 @@
45
47
  "@semantic-release/npm": "^13.1.3",
46
48
  "@semantic-release/release-notes-generator": "^14.1.0",
47
49
  "eslint": "^9.15.0",
50
+ "eslint-config-prettier": "^10.1.8",
51
+ "eslint-plugin-prettier": "^5.5.5",
48
52
  "globals": "^15.12.0",
49
53
  "jest": "^29.7.0",
50
54
  "mock-fs": "^5.5.0",
55
+ "prettier": "^3.8.1",
51
56
  "semantic-release": "^25.0.2"
52
57
  }
53
58
  }