Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Change case refactor #506

Merged
merged 8 commits into from
Aug 6, 2024
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
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. The format

## [Unreleased]

### Added

- Add `camelCase`, `pascalCase`, `snakeCase` and `dashCase` functions ([#506](https://github.com/studiometa/js-toolkit/pull/506), [c753a16](https://github.com/studiometa/js-toolkit/commit/c753a16))
- Add a `memo` function as a simpler and smaller `memoize` alternative ([#506](https://github.com/studiometa/js-toolkit/pull/506), [980a0b3](https://github.com/studiometa/js-toolkit/commit/980a0b3))

### Changed

- Convert ref names to camelCase ([#338](https://github.com/studiometa/js-toolkit/issues/338), [#506](https://github.com/studiometa/js-toolkit/pull/506), [1f5dbd9](https://github.com/studiometa/js-toolkit/commit/1f5dbd9))

## [v3.0.0-alpha.6](https://github.com/studiometa/js-toolkit/compare/3.0.0-alpha.5..3.0.0-alpha.6) (2024-08-02)

### Changed
Expand All @@ -19,7 +28,6 @@ All notable changes to this project will be documented in this file. The format
- Fix a bug where refs could be undefined ([c11eb49](https://github.com/studiometa/js-toolkit/commit/c11eb49))
- ⚠️ Fix listening to unconfigured events ([#505](https://github.com/studiometa/js-toolkit/pull/505), [a1e8dc9](https://github.com/studiometa/js-toolkit/commit/a1e8dc9))


## [v3.0.0-alpha.5](https://github.com/studiometa/js-toolkit/compare/3.0.0-alpha.4..3.0.0-alpha.5) (2024-07-16)

### Changed
Expand Down
7 changes: 7 additions & 0 deletions packages/docs/.vitepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ function getUtilsSidebar() {
items: [
{ text: 'debounce', link: '/utils/debounce.html' },
{ text: 'keyCodes', link: '/utils/keyCodes.html' },
{ text: 'memo', link: '/utils/memo.html' },
{ text: 'memoize', link: '/utils/memoize.html' },
{ text: 'nextFrame', link: '/utils/nextFrame.html' },
{ text: 'nextMicrotask', link: '/utils/nextMicrotask.html' },
Expand Down Expand Up @@ -356,6 +357,12 @@ function getUtilsSidebar() {
link: '/utils/string/',
collapsed: true,
items: [
{ text: 'camelCase', link: '/utils/string/camelCase.html' },
{ text: 'dashCase', link: '/utils/string/dashCase.html' },
{ text: 'pascalCase', link: '/utils/string/pascalCase.html' },
{ text: 'snakeCase', link: '/utils/string/snakeCase.html' },
{ text: 'lowerCase', link: '/utils/string/lowerCase.html' },
{ text: 'upperCase', link: '/utils/string/upperCase.html' },
{ text: 'startsWith', link: '/utils/string/startsWith.html' },
{ text: 'endsWith', link: '/utils/string/endsWith.html' },
{ text: 'withLeadingCharacters', link: '/utils/string/withLeadingCharacters.html' },
Expand Down
16 changes: 8 additions & 8 deletions packages/docs/api/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ The [lazy import helpers](/api/helpers/#lazy-import-helpers) can be used to mana
- Type : `Array<String>`
- Default : `[]`

Define the refs of the components by specifying their name in the configuration. Multiple refs should be suffixed with `[]`.
Define the refs of the components by specifying their name in the configuration. Multiple refs should be suffixed with `[]`. Refs names can be configured and used in HTML following the `dash-case` pattern, and will be available in the `this.$refs` object following the `camelCase` pattern.

```html
<div data-component="Component">
Expand All @@ -132,8 +132,8 @@ Define the refs of the components by specifying their name in the configuration.
<li data-ref="items[]">#1</li>
</ul>
<ul>
<li data-ref="otherItems[]">#1</li>
<li data-ref="otherItems[]">#2</li>
<li data-ref="other-items[]">#1</li>
<li data-ref="other-items[]">#2</li>
</ul>
<!-- Refs can be prefixed by the name of their component (in HTML only) -->
<input data-ref="Component.input" type="text" />
Expand All @@ -144,13 +144,13 @@ Define the refs of the components by specifying their name in the configuration.
class Component extends Base {
static config = {
name: 'Component',
refs: ['btn', 'items[]', 'otherItems[]'],
refs: ['btn', 'items[]', 'other-items[]'],
};

mounted() {
this.$refs.btn; // <button data-ref="btn">Click me</button>
this.$refs.items; // [<li data-ref="items[]">#1</li>]
this.$refs.otherItems; // [<li data-ref="otherItems[]">#1</li>, <li data-ref="otherItems[]">#2</li>]
this.$refs.otherItems; // [<li data-ref="other-items[]">#1</li>, <li data-ref="other-items[]">#2</li>]
}
}
```
Expand Down Expand Up @@ -203,11 +203,11 @@ The debug logs are conditionnally rendered base on a `__DEV__` global variable w
**Example Webpack configuration**

```js
const { DefinePlugin } = require('webpack');
import webpack from 'webpack';

module.exports = {
export default {
plugins: [
new DefinePlugin({
new webpack.DefinePlugin({
__DEV__: JSON.stringify(process.env.NODE_ENV === 'development'),
}),
],
Expand Down
27 changes: 27 additions & 0 deletions packages/docs/utils/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# memo

Like the [`memoize` function](./memoize.html), but simpler and smaller.

The cache key will be generated by joining all the args together and the cache will never expire.

## Usage

```js
import { memo } from '@studiometa/js-toolkit/utils';

function heavyFunction(a, b) {
return a.replace(/foo/g, b);
}

const memoHeavyFunction = memo(heavyFunction);

memoHeavyFunction('foo', 'bar'); // bar
```

### Parameters

- `fn` (`Function`): the function to cache

### Return value

This function returns a new function which will cache the first function results.
19 changes: 19 additions & 0 deletions packages/docs/utils/string/camelCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# camelCase

Transform a string to `camelCase`.

## Usage

```js
import { camelCase } from '@studiometa/js-toolkit/utils';

camelCase('Some String Content'); // someStringContent
```

### Params

- `string` (`string`): The string to transform.

### Return value

- `string`: The transformed string.
20 changes: 20 additions & 0 deletions packages/docs/utils/string/dashCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# dashCase

Transform a string to `dash-case`.

## Usage

```js
import { dashCase } from '@studiometa/js-toolkit/utils';

dashCase('Some String Content'); // some-string-content
```

### Params

- `string` (`string`): The string to transform.

### Return value

- `string`: The transformed string.

20 changes: 20 additions & 0 deletions packages/docs/utils/string/lowerCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# lowerCase

Transform a string to `lowercase`. This function is an alias of `String.prototype.toLowercase()`.

## Usage

```js
import { lowerCase } from '@studiometa/js-toolkit/utils';

lowerCase('Some String Content'); // some string content
```

### Params

- `string` (`string`): The string to transform.

### Return value

- `string`: The transformed string.

19 changes: 19 additions & 0 deletions packages/docs/utils/string/pascalCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# pascalCase

Transform a string to `PascalCase`.

## Usage

```js
import { pascalCase } from '@studiometa/js-toolkit/utils';

pascalCase('Some String Content'); // SomeStringContent
```

### Params

- `string` (`string`): The string to transform.

### Return value

- `string`: The transformed string.
20 changes: 20 additions & 0 deletions packages/docs/utils/string/snakeCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# snakeCase

Transform a string to `snake_case`.

## Usage

```js
import { snakeCase } from '@studiometa/js-toolkit/utils';

snakeCase('Some String Content'); // some_string_content
```

### Params

- `string` (`string`): The string to transform.

### Return value

- `string`: The transformed string.

19 changes: 19 additions & 0 deletions packages/docs/utils/string/upperCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# upperCase

Transform a string to `UPPERCASE`. This function is an alias of `String.prototype.toUppercase()`.

## Usage

```js
import { upperCase } from '@studiometa/js-toolkit/utils';

upperCase('Some String Content'); // SOME STRING CONTENT
```

### Params

- `string` (`string`): The string to transform.

### Return value

- `string`: The transformed string.
85 changes: 11 additions & 74 deletions packages/js-toolkit/Base/managers/EventsManager.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,11 @@
import type { Base } from '../index.js';
import getAllProperties from '../../utils/object/getAllProperties.js';
import { isArray } from '../../utils/index.js';
import { dashCase, isArray, pascalCase } from '../../utils/index.js';
import { getEventTarget, eventIsNative, eventIsDefinedInConfig } from '../utils.js';
import { AbstractManager } from './AbstractManager.js';
import { normalizeRefName } from './RefsManager.js';
import { features } from '../features.js';

const names = new Map();
const normalizeRegex1 = /[A-Z]([A-Z].*)/g;
const normalizeRegex2 = /[^a-zA-Z\d\s:]/g;
const normalizeRegex3 = /(^\w|\s+\w)/g;

/**
* Normalize the given name to PascalCase, such as:
*
* ```
* sentence case => SentenceCase
* lowercase => Lowercase
* UPPERCASE => Uppercase
* kebab-case => KebabCase
* snake_case => SnakeCase
* camelCase => CamelCase
* PascalCase => PascalCase
* .class-selector => ClassSelector
* .bem__selector => BemSelector
* __id-selector => IdSelector
* .complex[class^ ="__"] => ComplexClass
* ```
*
* @param {string} name
* @returns {string}
*/
export function normalizeName(name: string): string {
if (!names.has(name)) {
names.set(
name,
name
.replaceAll(normalizeRegex1, (c) => c.toLowerCase())
.replaceAll(normalizeRegex2, ' ')
.replaceAll(normalizeRegex3, (c) => c.trim().toUpperCase())
.trim(),
);
}

return names.get(name);
}

const eventNames = new Map();

const normalizeEventRegex1 = /[A-Z]/g;
const normalizeEventRegex2 = /^-/;
/**
* Normalize the event names from PascalCase to kebab-case.
*
* @param {string} name
* @returns {string}
*/
export function normalizeEventName(name: string): string {
if (!eventNames.has(name)) {
eventNames.set(
name,
name
.replaceAll(normalizeEventRegex1, (c) => `-${c.toLowerCase()}`)
.replace(normalizeEventRegex2, ''),
);
}

return eventNames.get(name);
}

const regexes = new Map();

/**
Expand All @@ -94,9 +31,9 @@ function getRegex(regex: string): RegExp {
* @private
*/
function getEventNameByMethod(method: string, name = ''): string {
const regex = getRegex(`^on${normalizeName(name)}([A-Z].*)$`);
const regex = getRegex(`^on${pascalCase(name)}([A-Z].*)$`);
const [, event] = method.match(regex);
return normalizeEventName(event);
return dashCase(event);
}

/**
Expand All @@ -109,7 +46,7 @@ function getEventNameByMethod(method: string, name = ''): string {
*/
// eslint-disable-next-line no-use-before-define
function getEventMethodsByName(that: EventsManager, name = ''): string[] {
const regex = getRegex(`^on${normalizeName(name)}[A-Z].*$`);
const regex = getRegex(`^on${pascalCase(name)}[A-Z].*$`);
const key = regex.toString();

let methods = that.__methodsCache.get(key);
Expand Down Expand Up @@ -265,7 +202,7 @@ export class EventsManager extends AbstractManager {
*/
__rootElementHandler: EventListenerObject = {
handleEvent: (event: Event | CustomEvent) => {
const normalizedEventName = normalizeName(event.type);
const normalizedEventName = pascalCase(event.type);
const method = `on${normalizedEventName}`;
const isCustomEvent = event instanceof CustomEvent;

Expand All @@ -290,7 +227,7 @@ export class EventsManager extends AbstractManager {
* @returns {void}
*/
handleEvent: (event) => {
const normalizedEventName = normalizeName(event.type);
const normalizedEventName = pascalCase(event.type);
const method = `onDocument${normalizedEventName}`;

this.__base[method](normalizeParams({ event, target: document }));
Expand All @@ -308,7 +245,7 @@ export class EventsManager extends AbstractManager {
* @returns {void}
*/
handleEvent: (event) => {
const normalizedEventName = normalizeName(event.type);
const normalizedEventName = pascalCase(event.type);
const method = `onWindow${normalizedEventName}`;

this.__base[method](normalizeParams({ event, target: window }));
Expand All @@ -324,8 +261,8 @@ export class EventsManager extends AbstractManager {
const attributes = features.get('attributes');
const refName = normalizeRefName(ref.getAttribute(attributes.ref));

const normalizedRefName = normalizeName(refName);
const normalizedEventName = normalizeName(event.type);
const normalizedRefName = pascalCase(refName);
const normalizedEventName = pascalCase(event.type);
const method = `on${normalizedRefName}${normalizedEventName}`;

let index = 0;
Expand Down Expand Up @@ -355,8 +292,8 @@ export class EventsManager extends AbstractManager {
}))
.find(({ child }) => child);

const normalizedChildName = normalizeName(name);
const normalizedEventName = normalizeName(event.type);
const normalizedChildName = pascalCase(name);
const normalizedEventName = pascalCase(event.type);
const method = `on${normalizedChildName}${normalizedEventName}`;

const index = [...childrenManager[name]].indexOf(resolvedChild);
Expand Down
Loading
Loading