Skip to content

Commit

Permalink
Merge pull request #223 from kitsuyui/string
Browse files Browse the repository at this point in the history
Add @kitsuyui/string package
  • Loading branch information
kitsuyui authored Mar 30, 2024
2 parents e1da0cc + 3dfd7a0 commit 9b95ef2
Show file tree
Hide file tree
Showing 12 changed files with 497 additions and 0 deletions.
52 changes: 52 additions & 0 deletions packages/string/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# @kitsuyui/string

A simple string manipulation library

## Installation

### NPM

```bash
npm install @kitsuyui/string
```

### Yarn

```bash
yarn add @kitsuyui/string
```

### PNPM

```bash
pnpm add @kitsuyui/string
```

## Usage

### convertCase

```typescript
import { convertCase } from '@kitsuyui/string';

convertCase('helloWorld', 'kebab-case') // => `hello-world`
convertCase('hello-world', 'camelCase') // => `helloWorld`
convertCase('helloWorld', 'kebab-case') // => `hello-world`
convertCase('hello-world', 'camelCase') // => `helloWorld`
convertCase('hello-world', 'snake_case') // => `hello_world`
convertCase('hello-world', 'space separated') // => `hello world`
convertCase('hello-world', 'UpperCamelCase') // => `HelloWorld`
convertCase('hello-world', 'PascalCase') // => `HelloWorld`
convertCase('hello-world', 'lowerCamelCase') // => `helloWorld`
convertCase('hello-world', 'lowerPascalCase') // => `helloWorld`
convertCase('hello-world', 'SCREAMING_SNAKE_CASE') // => `HELLO_WORLD`
convertCase('hello-world', 'MACRO_CASE') // => `HELLO_WORLD`
convertCase('hello-world', 'Train-Case') // => `Hello-World`
convertCase('hello-world', 'dot.separated') // => `hello.world`
convertCase('hello-world', 'flatcase') // => `helloworld`
convertCase('hello-world', 'ALL CAPS') // => `HELLO WORLD`
```

## License

MIT
29 changes: 29 additions & 0 deletions packages/string/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@kitsuyui/string",
"version": "0.0.0",
"license": "MIT",
"author": "Yui Kitsu <[email protected]>",
"description": "A simple additional library for String",
"scripts": {
"build": "tsup src/index.ts --clean",
"dev": "pnpm build --watch"
},
"bin": {
"ts-playground-main": "./dist/main.js"
},
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"package.json"
],
"devDependencies": {}
}
26 changes: 26 additions & 0 deletions packages/string/src/capitalization/cases/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { describe, it, expect, jest } from '@jest/globals'

import { isValidCaseName } from '.'

describe('isValidCaseName', () => {
it('should return true for valid case names', () => {
expect(isValidCaseName('kebab-case')).toBe(true)
expect(isValidCaseName('snake_case')).toBe(true)
expect(isValidCaseName('space separated')).toBe(true)
expect(isValidCaseName('camelCase')).toBe(true)
expect(isValidCaseName('UpperCamelCase')).toBe(true)
expect(isValidCaseName('lowerCamelCase')).toBe(true)
expect(isValidCaseName('PascalCase')).toBe(true)
expect(isValidCaseName('lowerPascalCase')).toBe(true)
expect(isValidCaseName('SCREAMING_SNAKE_CASE')).toBe(true)
expect(isValidCaseName('MACRO_CASE')).toBe(true)
expect(isValidCaseName('Train-Case')).toBe(true)
expect(isValidCaseName('dot.separated')).toBe(true)
expect(isValidCaseName('flatcase')).toBe(true)
expect(isValidCaseName('ALL CAPS')).toBe(true)
})

it('should return false for invalid case names', () => {
expect(isValidCaseName('invalid')).toBe(false)
})
})
27 changes: 27 additions & 0 deletions packages/string/src/capitalization/cases/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export const ALL_CASES = [
'kebab-case',
'snake_case',
'space separated',
'camelCase',
'UpperCamelCase',
'lowerCamelCase',
'PascalCase', // equivalent to UpperCamelCase
'lowerPascalCase', // equivalent to lowerCamelCase
'SCREAMING_SNAKE_CASE',
'MACRO_CASE', // equivalent to SCREAMING_SNAKE_CASE
'Train-Case',
'dot.separated',
'flatcase',
'ALL CAPS',
] as const

export type Case = typeof ALL_CASES[number]

/**
* Check if a string is a valid Case Name
* @param caseText
* @returns
*/
export const isValidCaseName = (caseText: string): caseText is Case => {
return ALL_CASES.includes(caseText as Case)
}
37 changes: 37 additions & 0 deletions packages/string/src/capitalization/convert/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, it, expect, jest } from '@jest/globals'

import { convertCase } from '.'
import { ALL_CASES, type Case } from '../cases'

describe('convertCase', () => {
it('should work some simple examples', () => {
expect(convertCase('helloWorld', 'kebab-case')).toBe('hello-world')
expect(convertCase('hello-world', 'camelCase')).toBe('helloWorld')
expect(convertCase('hello-world', 'snake_case')).toBe('hello_world')
expect(convertCase('hello-world', 'space separated')).toBe('hello world')
expect(convertCase('hello-world', 'UpperCamelCase')).toBe('HelloWorld')
expect(convertCase('hello-world', 'PascalCase')).toBe('HelloWorld')
expect(convertCase('hello-world', 'lowerCamelCase')).toBe('helloWorld')
expect(convertCase('hello-world', 'lowerPascalCase')).toBe('helloWorld')
expect(convertCase('hello-world', 'SCREAMING_SNAKE_CASE')).toBe('HELLO_WORLD')
expect(convertCase('hello-world', 'MACRO_CASE')).toBe('HELLO_WORLD')
expect(convertCase('hello-world', 'Train-Case')).toBe('Hello-World')
expect(convertCase('hello-world', 'dot.separated')).toBe('hello.world')
expect(convertCase('hello-world', 'flatcase')).toBe('helloworld')
expect(convertCase('hello-world', 'ALL CAPS')).toBe('HELLO WORLD')
})

it('should convert text to all cases', () => {
const text = 'convert this text to all cases'
for (const toCase of ALL_CASES) {
const converted = convertCase(text, toCase)
expect(converted).toBeTruthy()
}
})

it('should throw an error for invalid case', () => {
const text = 'convert this text to all cases'
const toCase = 'invalid'
expect(() => convertCase(text, 'invalid' as Case)).toThrowError('Invalid Case: invalid')
})
})
17 changes: 17 additions & 0 deletions packages/string/src/capitalization/convert/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { splitToWords } from "../split"
import { joinWords } from "../join"
import { ALL_CASES, type Case } from "../cases"

const isValidCase = (caseText: string): caseText is Case => {
return ALL_CASES.includes(caseText as Case)
}


export const convertCase = (text: string, toCase: Case): string => {
if (!isValidCase(toCase)) {
throw new Error(`Invalid Case: ${toCase}`)
}
const words = splitToWords(text)
const converted = joinWords(words, toCase)
return converted
}
1 change: 1 addition & 0 deletions packages/string/src/capitalization/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { convertCase } from './convert'
101 changes: 101 additions & 0 deletions packages/string/src/capitalization/join/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { describe, it, expect, jest } from '@jest/globals'

import {
joinWords,
intoAllCaps,
intoFlatCase,
intoKebabCase,
intoScreamingSnakeCase,
intoSnakeCase,
intoSpaceSeparated,
intoTrainCase,
intoLowerCamelCase,
intoDotSeparated,
} from './index'
import type { Case } from '../cases'

describe('joinWords', () => {
it('should join words into the specified case', () => {
const words = ['join', 'words']
const kebab = joinWords(words, 'kebab-case')
expect(kebab).toBe('join-words')
})

it('should throw an error for invalid case', () => {
const words = ['join', 'words']
expect(() => joinWords(words, 'invalid' as Case)).toThrowError('Invalid Case: invalid')
expect(() => joinWords(words, undefined as unknown as Case)).toThrowError('Case is required')
})
})

describe('intoKebabCase', () => {
it('should join words into kebab case', () => {
const words = ['kebab', 'case']
const kebab = intoKebabCase(words)
expect(kebab).toBe('kebab-case')
})
})

describe('intoSnakeCase', () => {
it('should join words into snake case', () => {
const words = ['snake', 'case']
const snake = intoSnakeCase(words)
expect(snake).toBe('snake_case')
})
})

describe('intoSpaceSeparated', () => {
it('should join words into space separated', () => {
const words = ['space', 'separated']
const space = intoSpaceSeparated(words)
expect(space).toBe('space separated')
})
})

describe('intoAllCaps', () => {
it('should join words into all caps', () => {
const words = ['all', 'caps']
const caps = intoAllCaps(words)
expect(caps).toBe('ALL CAPS')
})
})

describe('intoScreamingSnakeCase', () => {
it('should join words into screaming snake case', () => {
const words = ['screaming', 'snake', 'case']
const snake = intoScreamingSnakeCase(words)
expect(snake).toBe('SCREAMING_SNAKE_CASE')
})
})

describe('intoTrainCase', () => {
it('should join words into train case', () => {
const words = ['train', 'case']
const train = intoTrainCase(words)
expect(train).toBe('Train-Case')
})
})

describe('intoFlatCase', () => {
it('should join words into flat case', () => {
const words = ['flat', 'case']
const flat = intoFlatCase(words)
expect(flat).toBe('flatcase')
})
})

describe('intoDotSeparated', () => {
it('should join words into dot separated', () => {
const words = ['dot', 'separated']
const dot = intoDotSeparated(words)
expect(dot).toBe('dot.separated')
})
})

describe('intoLowerCamelCase', () => {
it('should join words into lower camel case', () => {
const words = ['lower', 'camel', 'case']
const camel = intoLowerCamelCase(words)
expect(camel).toBe('lowerCamelCase')
})
})
Loading

0 comments on commit 9b95ef2

Please sign in to comment.