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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ npm-debug.log*
package-lock.json
/dist
/coverage
.yalc
.yalc/*
yalc.lock
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sysvale/show",
"version": "1.19.0",
"version": "1.20.0",
"description": "A set of components used at Sysvale",
"repository": {
"type": "git",
Expand Down
98 changes: 50 additions & 48 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,61 +16,63 @@ import { useDialog } from '@/composables/useDialog';

/** Utils */
import {
convertKeysToCamelCase,
convertKeysToSnakeCase,
removeAccents,
generateKey,
toThousands,
setupVeeValidateWrapper,
convertKeysToCamelCase,
convertKeysToSnakeCase,
removeAccents,
generateKey,
toThousands,
setupVeeValidateWrapper,
pluralize,
pluralizeWithCount,
pluralizeWords,
} from '../utils';
/* -------*/

export { useRequest, useDialog };
export { useRequest, useDialog, pluralize, pluralizeWithCount, pluralizeWords };

export default {
install(app: any, options = {
veeValidateOptions: {},
disabledFeatures: [],
}) {
const { veeValidateOptions, disabledFeatures } = options;
const veeValidateWrapper = setupVeeValidateWrapper(veeValidateOptions);
install(app: any, options = {
veeValidateOptions: {},
disabledFeatures: [],
}) {
const { veeValidateOptions, disabledFeatures } = options;
const veeValidateWrapper = setupVeeValidateWrapper(veeValidateOptions);

if (disabledFeatures.length > 0) {
app.provide('disabledFeatures', options.disabledFeatures);
}
if (disabledFeatures.length > 0) {
app.provide('disabledFeatures', options.disabledFeatures);
}

app.component('ShowRequestProvider', RequestProvider);
app.component('ShowRequestObserver', RequestObserver);
app.component('ShowRequestSelect', RequestSelect);
app.component('ShowForm', Form);
app.component('ShowField', Field);
app.component('ShowFieldArray', FieldArray);
app.component('ShowFormWizard', FormWizard);
app.component('ShowFeatureWrapper', FeatureWrapper);
app.component('ShowRequestProvider', RequestProvider);
app.component('ShowRequestObserver', RequestObserver);
app.component('ShowRequestSelect', RequestSelect);
app.component('ShowForm', Form);
app.component('ShowField', Field);
app.component('ShowFieldArray', FieldArray);
app.component('ShowFormWizard', FormWizard);
app.component('ShowFeatureWrapper', FeatureWrapper);

const utils = {
$showConvertKeysToCamelCase: convertKeysToCamelCase,
$showConvertKeysToSnakeCase: convertKeysToSnakeCase,
$showRemoveAccents: removeAccents,
$showGenerateKey: generateKey,
$showToThousands: toThousands,
};

const utils = {
$showConvertKeysToCamelCase: convertKeysToCamelCase,
$showConvertKeysToSnakeCase: convertKeysToSnakeCase,
$showRemoveAccents: removeAccents,
$showGenerateKey: generateKey,
$showToThousands: toThousands,
};
const version = Number(app.version.split('.')[0]);

if (version <= 2) {
throw new Error('Essa versão só é compatível com projetos que possuem o Vue 3. Para projetos com a Vue 2, utilize a versão 0.3.0 ou inferior');
}

if (version > 2) {
// ficará disponível apenas com o uso do Options API
Object.keys(utils).forEach((key: string) => {
app.config.globalProperties[key] = utils[key];
});

const version = Number(app.version.split('.')[0]);

if (version <= 2) {
throw new Error('Essa versão só é compatível com projetos que possuem o Vue 3. Para projetos com a Vue 2, utilize a versão 0.3.0 ou inferior');
}

if (version > 2) {
// ficará disponível apenas com o uso do Options API
Object.keys(utils).forEach((key: string) => {
app.config.globalProperties[key] = utils[key];
});

// wrapper do vee-validate
app.config.globalProperties.$showVeeValidate = veeValidateWrapper;
}
},
}
// wrapper do vee-validate
app.config.globalProperties.$showVeeValidate = veeValidateWrapper;
}
},
}
1 change: 1 addition & 0 deletions src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export { default as getFirstErrorMessage } from './getFirstErrorMessage';
export { default as removeAccents } from './removeAccents';
export { default as generateKey } from './generateKey';
export { default as toThousands } from './toThousands';
export { pluralize, pluralizeWithCount, pluralizeWords } from './pluralize';
export { default as setupVeeValidateWrapper } from './setupVeeValidateWrapper';
87 changes: 87 additions & 0 deletions src/utils/pluralize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const irregulars: Record<string, string> = {
pão: 'pães',
mão: 'mãos',
irmão: 'irmãos',
capitão: 'capitães',
cidadão: 'cidadãos',
cão: 'cães',
alemão: 'alemães',
mal: 'males',
órgão: 'órgãos',
nível: 'níveis'
};

export function pluralize(
count: number | string | null = null,
word: string,
customPlural: string = '',
customIrregulars: Record<string, string> = {}
): string {

let innerIrregulars = {
...irregulars,
...customIrregulars
}

if (typeof count === 'string') {
word = count;
count = null;
}

const absCount = Math.abs(count ?? 2);

// Quantidades insuficientes para aplicação do plural
if (absCount < 2) return word;

// Sufixo personalizado fornecido por quem chama a função
if (customPlural) return customPlural;

// Cenário em que a palavra tem plural irregular
if (innerIrregulars[word]) return innerIrregulars[word];

// Palavras invariáveis terminadas em s ou x
if (word.endsWith('s') || word.endsWith('x')) return word;

// Exceções do -ão (padrão geral: -ões)
if (word.endsWith('ão')) return word.slice(0, -2) + 'ões';

// -m -> -ns
if (word.endsWith('m')) return word.slice(0, -1) + 'ns';

// -r, -z -> +es
if (word.endsWith('r') || word.endsWith('z')) return word + 'es';

// -ol → -óis
if (word.endsWith('ol')) return word.slice(0, -2) + 'óis';

// -al, -ul → -ais, -uis
if (/[au]l$/.test(word)) return word.slice(0, -1) + 'is';

// -el → -éis
if (word.endsWith('el')) return word.slice(0, -2) + 'éis';

// -il → -is (oxítonas) [simplificado]
if (word.endsWith('il')) return word.slice(0, -2) + 'is';

// Regra geral para vogais finais
if (/[aeiou]$/.test(word)) return word + 's';

//Fallback
return word;
}

export function pluralizeWithCount(...args: Parameters<typeof pluralize>): string {
const [count] = args;
return `${count} ${pluralize(...args)}`;
}

export function pluralizeWords(
count: number | string | null,
words: string[],
customPlural: string[] | string = '',
customIrregulars: Record<string, string> = {}
): string {
let pluralizedWords = words.map((word, index) => pluralize(count, word, customPlural[index] ?? customPlural, customIrregulars));

return `${pluralizedWords.join(' ')}`;
}
115 changes: 115 additions & 0 deletions tests/utils/pluralize.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { describe, test, expect } from 'vitest';
import { pluralize, pluralizeWords, pluralizeWithCount } from '../../src/utils/pluralize'; // Adjust the path

describe('pluralize()', () => {
test('returns same word if count is 1', () => {
expect(pluralize(1, 'carro')).toBe('carro');
});

test('adds "s" for regular words ending in vowel', () => {
expect(pluralize(2, 'banana')).toBe('bananas');
});

test('uses custom plural if provided', () => {
expect(pluralize(2, 'livro')).not.toBe('livrozinhos');
expect(pluralize(2, 'livro', 'livrozinhos')).toBe('livrozinhos');
});

test('does not change words ending in s or x', () => {
expect(pluralize(3, 'tórax')).toBe('tórax');
expect(pluralize(3, 'lápis')).toBe('lápis');
});

test('converts -ão to -ões', () => {
expect(pluralize(2, 'avião')).toBe('aviões');
});

test('converts some irregulars properly', () => {
expect(pluralize(2, 'pão')).toBe('pães');
expect(pluralize(2, 'alemão')).toBe('alemães');
});

test('convert custom irregulars properly', () => {
expect(pluralize(2, 'órgão')).toBe('órgãos');
expect(pluralize(2, 'cônsul')).not.toBe('cônsules');
expect(pluralize(2, 'cônsul', undefined, { cônsul: 'cônsules'})).toBe('cônsules');
expect(pluralize(2, 'maçã', undefined, { maçã: 'maçãs'})).toBe('maçãs');
});

test('converts -m to -ns', () => {
expect(pluralize(2, 'homem')).toBe('homens');
});

test('adds "es" for words ending in r or z', () => {
expect(pluralize(2, 'luz')).toBe('luzes');
expect(pluralize(2, 'motor')).toBe('motores');
});

test('converts-ol to -óis', () => {
expect(pluralize(2, 'sol')).toBe('sóis');
});

test('converts -al, -ul to -ais, -uis', () => {
expect(pluralize(2, 'animal')).toBe('animais');
expect(pluralize(2, 'azul')).toBe('azuis');
});

test('converts -el to -éis', () => {
expect(pluralize(2, 'papel')).toBe('papéis');
});

test('converts -il to -is', () => {
expect(pluralize(2, 'fuzil')).toBe('fuzis');
});

test('uses plural when count is negative', () => {
expect(pluralize(-3, 'avião')).toBe('aviões');
});

test('does not use plural when count is zero', () => {
expect(pluralize(0, 'mapa')).toBe('mapa');
});

test('defaults count to 2 if null or undefined', () => {
expect(pluralize(null, 'livro')).toBe('livros');
});

test('treats first param as word if count is a string', () => {
expect(pluralize('carro', '')).toBe('carros');
});
});

describe('pluralizeWithCount()', () => {
test('includes the count in the result', () => {
expect(pluralizeWithCount(1, 'carro')).toBe('1 carro');
expect(pluralizeWithCount(2, 'carro')).toBe('2 carros');
});

test('works with custom plural', () => {
expect(pluralizeWithCount(2, 'livro', 'livrozinhos')).toBe('2 livrozinhos');
});
});

describe('pluralizeWords()', () => {
test('works with one word', () => {
expect(pluralizeWords(0, ['papel'])).toBe('papel');
expect(pluralizeWords(1, ['papel'])).toBe('papel');
expect(pluralizeWords(2, ['papel'])).toBe('papéis');
});

test('works with two words', () => {
expect(pluralizeWords(0, ['avião', 'antigo'])).toBe('avião antigo');
expect(pluralizeWords(1, ['avião', 'antigo'])).toBe('avião antigo');
expect(pluralizeWords(2, ['avião', 'antigo'])).toBe('aviões antigos');
});

test('works with three words', () => {
expect(pluralizeWords(0, ['moto', 'branca', 'escolhida'])).toBe('moto branca escolhida');
expect(pluralizeWords(1, ['moto', 'branca', 'escolhida'])).toBe('moto branca escolhida');
expect(pluralizeWords(2, ['moto', 'branca', 'escolhida'])).toBe('motos brancas escolhidas');
});

test('works with custom plurals', () => {
expect(pluralizeWords(2, ['o', 'avião', 'velho'], ['os', 'aviõezinhos', 'velhos'])).toBe('os aviõezinhos velhos');
});
});