Skip to content

Commit e653916

Browse files
authored
Merge pull request #2 from ioncakephper:feature/add-new-function
Update project files and add string normalization utility
2 parents a82a44a + d633d63 commit e653916

File tree

10 files changed

+127
-41
lines changed

10 files changed

+127
-41
lines changed

.eslintrc.json

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,10 @@
55
"node": true,
66
"jest/globals": true
77
},
8-
"extends": [
9-
"eslint:recommended",
10-
"plugin:jest/recommended",
11-
"prettier"
12-
],
8+
"extends": ["eslint:recommended", "plugin:jest/recommended", "prettier"],
139
"parserOptions": {
1410
"ecmaVersion": "latest"
1511
},
16-
"plugins": [
17-
"jest"
18-
],
12+
"plugins": ["jest"],
1913
"rules": {}
20-
}
14+
}

.github/workflows/ci.yml

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Node.js CI
22

33
on:
44
push:
5-
branches: [ "main" ]
5+
branches: ['main']
66
pull_request:
7-
branches: [ "main" ]
7+
branches: ['main']
88

99
jobs:
1010
build:
@@ -15,17 +15,17 @@ jobs:
1515
node-version: [18.x, 20.x]
1616

1717
steps:
18-
- uses: actions/checkout@v4
19-
- name: Use Node.js ${{ matrix.node-version }}
20-
uses: actions/setup-node@v4
21-
with:
22-
node-version: ${{ matrix.node-version }}
23-
cache: 'npm'
24-
- name: Install dependencies
25-
run: npm ci
26-
- name: Lint code
27-
run: npm run lint
28-
- name: Check formatting
29-
run: npm run format
30-
- name: Run tests
31-
run: npm test
18+
- uses: actions/checkout@v4
19+
- name: Use Node.js ${{ matrix.node-version }}
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: ${{ matrix.node-version }}
23+
cache: 'npm'
24+
- name: Install dependencies
25+
run: npm ci
26+
- name: Lint code
27+
run: npm run lint
28+
- name: Check formatting
29+
run: npm run format
30+
- name: Run tests
31+
run: npm test

.prettierrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
"singleQuote": true,
55
"printWidth": 80,
66
"tabWidth": 2
7-
}
7+
}

README.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ This template provides a solid foundation for any new JavaScript project, ensuri
66

77
## Features
88

9-
- **Linting** with [ESLint](https://eslint.org/) to find and fix problems in your JavaScript code.
10-
- **Formatting** with [Prettier](https://prettier.io/) for a consistent code style.
11-
- **Testing** with [Jest](https://jestjs.io/) as the testing framework.
12-
- **CI/CD** with [GitHub Actions](https://github.com/features/actions) to automate linting, formatting checks, and testing on every push and pull request.
13-
- **Pre-commit Hooks** with [Husky](https://typicode.github.io/husky/) and [lint-staged](https://github.com/okonet/lint-staged) to lint and format your code before you even commit it.
9+
- **Linting** with [ESLint](https://eslint.org/) to find and fix problems in your JavaScript code.
10+
- **Formatting** with [Prettier](https://prettier.io/) for a consistent code style.
11+
- **Testing** with [Jest](https://jestjs.io/) as the testing framework.
12+
- **CI/CD** with [GitHub Actions](https://github.com/features/actions) to automate linting, formatting checks, and testing on every push and pull request.
13+
- **Pre-commit Hooks** with [Husky](https://typicode.github.io/husky/) and [lint-staged](https://github.com/okonet/lint-staged) to lint and format your code before you even commit it.
1414

1515
## Getting Started
1616

@@ -21,6 +21,7 @@ Click the "Use this template" button on the GitHub repository page to create a n
2121
### Manual Setup
2222

2323
1. Clone the repository:
24+
2425
```bash
2526
git clone https://github.com/your-username/js-quality-starter.git
2627
cd js-quality-starter
@@ -35,11 +36,11 @@ Click the "Use this template" button on the GitHub repository page to create a n
3536

3637
In the project directory, you can run:
3738

38-
- `npm test`: Runs the tests using Jest.
39-
- `npm run lint`: Lints all `.js` files in the project.
40-
- `npm run lint:fix`: Lints and automatically fixes fixable issues.
41-
- `npm run format`: Checks for formatting issues with Prettier.
42-
- `npm run format:fix`: Formats all supported files with Prettier.
39+
- `npm test`: Runs the tests using Jest.
40+
- `npm run lint`: Lints all `.js` files in the project.
41+
- `npm run lint:fix`: Lints and automatically fixes fixable issues.
42+
- `npm run format`: Checks for formatting issues with Prettier.
43+
- `npm run format:fix`: Formats all supported files with Prettier.
4344

4445
## How It Works
4546

@@ -58,4 +59,4 @@ The `.github/workflows/ci.yml` file defines a GitHub Actions workflow that runs
5859
3. Runs `npm run format` to check for formatting errors.
5960
4. Runs `npm test` to execute the test suite.
6061

61-
This ensures that all code in the `main` branch is high quality and passes all checks.
62+
This ensures that all code in the `main` branch is high quality and passes all checks.

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ const config = {
55
coverageProvider: 'v8',
66
};
77

8-
module.exports = config;
8+
module.exports = config;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@
3737
"prettier --write"
3838
]
3939
}
40-
}
40+
}

src/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
/**
2+
* Adds two numbers together.
3+
* @param {number} a The first number.
4+
* @param {number} b The second number.
5+
* @returns {number} The sum of the two numbers.
6+
*/
17
function add(a, b) {
28
return a + b;
39
}
410

5-
module.exports = add;
11+
module.exports = add;

src/index.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ describe('add function', () => {
88
test('should handle negative numbers', () => {
99
expect(add(-1, -1)).toBe(-2);
1010
});
11-
});
11+
});

src/utils/normalize-string.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Normalizes a string by trimming whitespace, converting to lowercase,
3+
* replacing non-alphanumeric characters with dashes, collapsing multiple dashes,
4+
* and removing leading/trailing dashes. This is commonly used to create URL-friendly "slugs".
5+
*
6+
* @param {string} str The input string to normalize.
7+
* @returns {string} The normalized string.
8+
* @throws {Error} If the input is null or undefined.
9+
*/
10+
function normalizeString(str) {
11+
if (str === null || str === undefined) {
12+
throw new Error('Input cannot be null or undefined.');
13+
}
14+
15+
let s = String(str);
16+
17+
s = s.trim();
18+
s = s.toLowerCase();
19+
20+
// Replace non-alphanumeric (excluding dash and underscore) with a dash
21+
s = s.replace(/[^a-z0-9_-]/g, '-');
22+
23+
// Replace multiple dashes with a single dash
24+
s = s.replace(/-+/g, '-');
25+
26+
// Remove leading/trailing dashes
27+
s = s.replace(/^-+|-+$/g, '');
28+
29+
return s;
30+
}
31+
32+
module.exports = normalizeString;

src/utils/normalize-string.test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const normalizeString = require('./normalize-string');
2+
3+
describe('normalizeString', () => {
4+
test('should convert a basic string with spaces to kebab-case', () => {
5+
expect(normalizeString('Hello World')).toBe('hello-world');
6+
});
7+
8+
test('should trim leading and trailing whitespace', () => {
9+
expect(normalizeString(' leading and trailing ')).toBe(
10+
'leading-and-trailing'
11+
);
12+
});
13+
14+
test('should convert the entire string to lowercase', () => {
15+
expect(normalizeString('UPPERCASE STRING')).toBe('uppercase-string');
16+
});
17+
18+
test('should replace various special characters with a dash', () => {
19+
expect(normalizeString('a!b@c#d$e%f^g&h*i(j)k')).toBe(
20+
'a-b-c-d-e-f-g-h-i-j-k'
21+
);
22+
});
23+
24+
test('should collapse multiple dashes and spaces into a single dash', () => {
25+
expect(normalizeString('multiple---dashes')).toBe('multiple-dashes');
26+
expect(normalizeString('a b c')).toBe('a-b-c');
27+
});
28+
29+
test('should remove leading and trailing dashes', () => {
30+
expect(normalizeString('-leading-and-trailing-')).toBe(
31+
'leading-and-trailing'
32+
);
33+
});
34+
35+
test('should handle a complex mix of operations correctly', () => {
36+
expect(normalizeString(' --My Awesome Post #1! --')).toBe(
37+
'my-awesome-post-1'
38+
);
39+
});
40+
41+
test('should return an empty string if the input is an empty string', () => {
42+
expect(normalizeString('')).toBe('');
43+
});
44+
45+
test('should throw an error for null or undefined input', () => {
46+
expect(() => normalizeString(null)).toThrow(
47+
'Input cannot be null or undefined.'
48+
);
49+
expect(() => normalizeString(undefined)).toThrow(
50+
'Input cannot be null or undefined.'
51+
);
52+
});
53+
});

0 commit comments

Comments
 (0)