Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
name: Github packages NPM publish on release

name: Release
on:
release:
types: [created]
push:
branches:
- main

permissions:
contents: read # for checkout

jobs:
publish-github-registry:
release:
name: Release
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
registry-url: https://npm.pkg.github.com
- name: Install dependencies
run: npm ci
- name: test
run: npm test
- name: Publish
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install dependencies
run: npm clean-install
- name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
run: npm audit signatures
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
node_modules
DS_Store
.DS_Store
.npmrc
16 changes: 16 additions & 0 deletions .lfifyrc-sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"entry": "./",
"include": [
"**/*.{js,ts,jsx,tsx}",
"**/*.{json,md}",
"**/*.{css,scss}",
"**/*.{html,vue}"
],
"exclude": [
"node_modules/**",
".git/**",
"dist/**",
"build/**",
"coverage/**"
]
}
31 changes: 31 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Jest Tests Debug",
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
"args": [
"--runInBand",
"--watchAll=false",
"--testTimeout=100000",
"--detectOpenHandles"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/index.cjs"
}
]
}
91 changes: 28 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,81 +1,46 @@
# LFify

> ⚠️ **Warning**: All files must be encoded in UTF-8. The library is being developed to automatically convert UTF-8 with BOM to UTF-8 without BOM. Using different encodings may cause unexpected issues.

A lightweight Node.js library to convert CRLF to LF line endings.
It is useful when your development environment is Windows.

웹 개발자에게 Windows OS PC를 제공하는 우리 회사, 당장 반성하라!! 뭐만 하면 windows-cp-949 인코딩에 CRLF 라인피드 때문에 문제가 생겨요. Node.js 개발자한테 Windows PC 제공, 이거 법적으로 금지해야 해요.

# Features

- Exclude files from your `.gitignore`
- Exclude `.git` and `node_modules` directories on default
- Recursive conversion
- Supports multiple file extensions(generally used on Web Development)

# Installation

> If you do not have a Github personal access token, please create **CLASSIC** token that has `packages: read` permission.

first, edit your `.npmrc` file.

```bash
@gyeonghokim:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=<your-github-personal-access-token>
```

then, install it.

```bash
npm install --save-dev @gyeonghokim/lfify
```

# Usage

## Basic Usage
## Getting started

if you do not want to install it, you can use it with `npx`, however, you still need to specify registry and auth token in your `.npmrc` file.
create .lfifyrc.json

```bash
npx @gyeonghokim/lfify
```json
{
"entry": "./",
"include": [
"**/*.{js,ts,jsx,tsx}",
"**/*.{json,md}",
"**/*.{css,scss}",
"**/*.{html,vue}"
],
"exclude": [
"node_modules/**",
".git/**",
"dist/**",
"build/**",
"coverage/**"
]
}
```

## Specify Custom Directory
and then

```bash
npx @gyeonghokim/lfify ./path/to/your/project
```

## Script on your `package.json`

```json
"scripts": {
"lfify": "@gyeonghokim/lfify"
}
npx lifify
```

# Supported File Extensions

- JavaScript: `.js`, `.jsx`, `.cjs`, `.mjs`
- TypeScript: `.ts`, `.tsx`
- Web: `.html`, `.css`, `.scss`, `.vue`
- Markup/Config: `.json`, `.xml`, `.yml`, `.yaml`, `.md`
- Other: `.txt`, `.env`

# Features in Detail

1. Gitignore Support
Automatically reads and respects your .gitignore patterns
Skips ignored files and directories
you can add options below.

2. Smart Processing
Only modifies files that actually need conversion
Preserves file encoding
Provides detailed logging of all operations
## Options

3. Safe Operation
Automatically excludes binary files
Built-in protection for critical directories
Error handling with detailed logging
| Option | Description |
|--------|-------------|
| `--config <path>` | Specify a custom path for the configuration file. Default is `.lfifyrc.json` in the current directory. |

# Development

Expand Down
54 changes: 54 additions & 0 deletions __mocks__/fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const fs = jest.createMockFromModule('fs');

const mockFiles = new Map();

function __setMockFiles(newMockFiles) {
mockFiles.clear();
for (const [path, content] of Object.entries(newMockFiles)) {
mockFiles.set(path, content);
}
}

function __setConfig(stringifiedConfig, path = '.lfifyrc.json') {
mockFiles.set(path, stringifiedConfig);
}

const promises = {
/* eslint-disable-next-line no-unused-vars */
readFile: jest.fn().mockImplementation((path, ...rest) => {
if (mockFiles.has(path)) {
return Promise.resolve(mockFiles.get(path));
}
return Promise.reject(new Error(`ENOENT: no such file or directory, open '${path}'`));
}),

writeFile: jest.fn().mockImplementation((path, content) => {
mockFiles.set(path, content);
return Promise.resolve();
}),

/* eslint-disable-next-line no-unused-vars */
readdir: jest.fn().mockImplementation((path, ...rest) => {
const entries = [];
for (const filePath of mockFiles.keys()) {
if (filePath.startsWith(path)) {
const relativePath = filePath.slice(path.length + 1);
const name = relativePath.split('/')[0];
if (name && !entries.some(e => e.name === name)) {
entries.push({
name,
isFile: () => !name.includes('/'),
isDirectory: () => name.includes('/')
});
}
}
}
return Promise.resolve(entries);
})
};

fs.promises = promises;
fs.__setMockFiles = __setMockFiles;
fs.__setConfig = __setConfig;

module.exports = fs;
23 changes: 23 additions & 0 deletions __mocks__/micromatch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const micromatch = jest.createMockFromModule('micromatch');

micromatch.isMatch = jest.fn().mockImplementation((filePath, patterns) => {
if (!Array.isArray(patterns)) {
patterns = [patterns];
}

// 간단한 glob 패턴 매칭 구현
return patterns.some(pattern => {
// 정확한 매칭
if (pattern === filePath) return true;

// 와일드카드 매칭
const regexPattern = pattern
.replace(/\./g, '\\.')
.replace(/\*/g, '.*')
.replace(/\?/g, '.');

return new RegExp(`^${regexPattern}$`).test(filePath);
});
});

module.exports = micromatch;
17 changes: 17 additions & 0 deletions __mocks__/path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const path = jest.createMockFromModule('path');

const actualPath = jest.requireActual('path');

path.join = jest.fn().mockImplementation((...paths) => {
return actualPath.join(...paths);
});

path.resolve = jest.fn().mockImplementation((...paths) => {
return actualPath.resolve(...paths);
});

path.relative = jest.fn().mockImplementation((from, to) => {
return actualPath.relative(from, to);
});

module.exports = path;
Loading