-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added build workflow and unit tests.
- Loading branch information
Showing
23 changed files
with
597 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name: Build Vue3 Template | ||
|
||
on: | ||
push: | ||
branches: | ||
- dev | ||
workflow_dispatch: | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
- run: | | ||
npm ci | ||
npm run build | ||
npm run test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { describe, it, expect } from "vitest"; | ||
|
||
import { orderBy, orderByDescending } from "../arrayUtils"; | ||
|
||
type User = { | ||
name: string; | ||
email?: string; | ||
}; | ||
|
||
describe("arrayUtils.orderBy", () => { | ||
it.concurrent("should sort an empty array", () => { | ||
expect(orderBy([]).join(";")).toBe(""); | ||
expect(orderBy([], "name").join(";")).toBe(""); | ||
expect(orderBy([], undefined, true).join(";")).toBe(""); | ||
expect(orderBy([], "name", true).join(";")).toBe(""); | ||
}); | ||
|
||
it.concurrent("should sort ascendingly a primitive array", () => { | ||
expect(orderBy([3, undefined, 1, 2]).join(",")).toBe("1,2,3,"); | ||
expect(orderBy(["orange", "mango", "apple"], undefined, false).join("|")).toBe("apple|mango|orange"); | ||
}); | ||
|
||
it.concurrent("should sort ascendingly an object array by key", () => { | ||
const users: User[] = [{ name: "Charles" }, { name: "Christopher" }, { name: "Abby" }]; | ||
expect( | ||
orderBy(users, "name") | ||
.map(({ name }) => name) | ||
.join("|") | ||
).toBe("Abby|Charles|Christopher"); | ||
expect( | ||
orderBy(users, "name", false) | ||
.map(({ name }) => name) | ||
.join("|") | ||
).toBe("Abby|Charles|Christopher"); | ||
}); | ||
|
||
it.concurrent("should sort descendingly a primitive array", () => { | ||
expect(orderBy([3, 1, undefined, 2], undefined, true).join(",")).toBe("3,2,1,"); | ||
expect(orderBy(["orange", "apple", "mango"], undefined, true).join("|")).toBe("orange|mango|apple"); | ||
}); | ||
|
||
it.concurrent("should sort descendingly an object array by key", () => { | ||
const users: User[] = [{ name: "Charles", email: "carlosluyz@gmail.com" }, { name: "Christopher" }, { name: "Abby", email: "xxxabbyxxx@hotmail.com" }]; | ||
expect( | ||
orderBy(users, "email", true) | ||
.map(({ name }) => name) | ||
.join("|") | ||
).toBe("Abby|Charles|Christopher"); | ||
}); | ||
}); | ||
|
||
describe("arrayUtils.orderByDescending", () => { | ||
it.concurrent("should sort descendingly a primitive array", () => { | ||
expect(orderByDescending(["Acura", "Nissan", "Chevrolet"]).join(", ")).toBe("Nissan, Chevrolet, Acura"); | ||
expect(orderByDescending([undefined, "Acura", "Nissan", "Chevrolet"]).join(", ")).toBe("Nissan, Chevrolet, Acura, "); | ||
}); | ||
|
||
it.concurrent("should sort descendingly an empty array", () => { | ||
expect(orderByDescending([]).join("|")).toBe(""); | ||
expect(orderByDescending([], "name").join("|")).toBe(""); | ||
}); | ||
|
||
it.concurrent("should sort descendingly an object array", () => { | ||
const users: User[] = [{ name: "Charles", email: "carlosluyz@gmail.com" }, { name: "Christopher" }, { name: "Abby", email: "xxxabbyxxx@hotmail.com" }]; | ||
expect( | ||
orderByDescending(users, "email") | ||
.map(({ name }) => name) | ||
.join("|") | ||
).toBe("Abby|Charles|Christopher"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { describe, it, expect } from "vitest"; | ||
|
||
import { assign, isEmpty } from "../objectUtils"; | ||
|
||
type User = { | ||
name: string; | ||
email?: string; | ||
}; | ||
|
||
describe("objectUtils.assign", () => { | ||
it.concurrent("should assign a value to a key", () => { | ||
const user: User = { name: "Charles Luiz" }; | ||
assign(user, "name", "Carlos Luyz"); | ||
expect(user.name).toBe("Carlos Luyz"); | ||
}); | ||
|
||
it.concurrent("should assign a value to an optional key", () => { | ||
const user: User = { name: "Charles Luiz" }; | ||
assign(user, "email", "carlosluyz@gmail.com"); | ||
expect(user.email).toBe("carlosluyz@gmail.com"); | ||
}); | ||
|
||
it.concurrent("should assign undefined to an optional key", () => { | ||
const user: User = { name: "Charles Luis", email: "carlosluyz@gmail.com" }; | ||
assign(user, "email", undefined); | ||
expect(user.email).toBeUndefined(); | ||
}); | ||
}); | ||
|
||
describe("objectUtils.isEmpty", () => { | ||
it.concurrent("should return false if the object has at least one key", () => { | ||
const user: User = { name: "Charles Luiz" }; | ||
expect(isEmpty(user)).toBe(false); | ||
user.email = "carlosluyz@gmail.com"; | ||
expect(isEmpty(user)).toBe(false); | ||
}); | ||
|
||
it.concurrent("should return true if the object has no key", () => { | ||
const obj: any = {}; | ||
expect(isEmpty(obj)).toBe(true); | ||
obj.key = true; | ||
delete obj.key; | ||
expect(isEmpty(obj)).toBe(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { describe, it, expect } from "vitest"; | ||
|
||
import { combineURL, isAbsoluteURL, isDigit, isLetter, isLetterOrDigit, shortify, slugify, unaccent } from "../stringUtils"; | ||
|
||
describe("stringUtils.combineURL", () => { | ||
it.concurrent("should combine the segments with a slash (/)", () => { | ||
expect(combineURL()).toBe("/"); | ||
expect(combineURL("Hello World!")).toBe("/Hello World!"); | ||
expect(combineURL("hello", "world")).toBe("/hello/world"); | ||
expect(combineURL("http://api.google.com", "users/123")).toBe("http://api.google.com/users/123"); | ||
expect(combineURL("https://api.google.com", "users", "123")).toBe("https://api.google.com/users/123"); | ||
}); | ||
|
||
it.concurrent("should ignore empty values", () => { | ||
expect(combineURL("")).toBe("/"); | ||
expect(combineURL(" ")).toBe("/"); | ||
expect(combineURL("", "api", "user")).toBe("/api/user"); | ||
expect(combineURL(" ", "api", "user")).toBe("/api/user"); | ||
expect(combineURL("api", "", "user")).toBe("/api/user"); | ||
expect(combineURL("api", " ", "user")).toBe("/api/user"); | ||
expect(combineURL("api", "user", "")).toBe("/api/user"); | ||
expect(combineURL("api", "user", " ")).toBe("/api/user"); | ||
}); | ||
|
||
it.concurrent("should ignore undefined values", () => { | ||
const u: any = undefined; | ||
expect(combineURL(u)).toBe("/"); | ||
expect(combineURL(u, "api", "user")).toBe("/api/user"); | ||
expect(combineURL("api", u, "user")).toBe("/api/user"); | ||
expect(combineURL("api", "user", u)).toBe("/api/user"); | ||
}); | ||
|
||
it.concurrent("should remove starting & ending slashes (/) from segments", () => { | ||
expect(combineURL("/api", "users/123")).toBe("/api/users/123"); | ||
expect(combineURL("api", "users/123/")).toBe("/api/users/123"); | ||
expect(combineURL("/api", "users/123/")).toBe("/api/users/123"); | ||
}); | ||
}); | ||
|
||
describe("stringUtils.isAbsoluteURL", () => { | ||
it.concurrent("should return false when input string is not an absolute URL", () => { | ||
expect(isAbsoluteURL("")).toBe(false); | ||
expect(isAbsoluteURL(" ")).toBe(false); | ||
expect(isAbsoluteURL("/api/users/123")).toBe(false); | ||
}); | ||
|
||
it.concurrent("should return true when input string is an absolute URL", () => { | ||
expect(isAbsoluteURL("http://api.test.com/users/123")).toBe(true); | ||
expect(isAbsoluteURL("https://api.test.com/users/123")).toBe(true); | ||
expect(isAbsoluteURL("ftp://api.test.com/users/123")).toBe(true); | ||
}); | ||
}); | ||
|
||
describe("stringUtils.isDigit", () => { | ||
it.concurrent("should return false when input character is not a digit", () => { | ||
expect(isDigit("")).toBe(false); | ||
expect(isDigit(" ")).toBe(false); | ||
expect(isDigit("A")).toBe(false); | ||
}); | ||
|
||
it.concurrent("should return true when input character is a digit", () => { | ||
expect(isDigit("0")).toBe(true); | ||
expect(isDigit("4")).toBe(true); | ||
}); | ||
}); | ||
|
||
describe("stringUtils.isLetter", () => { | ||
it.concurrent("should return false when input character is not a letter", () => { | ||
expect(isLetter("")).toBe(false); | ||
expect(isLetter(" ")).toBe(false); | ||
expect(isLetter("0")).toBe(false); | ||
expect(isLetter("|")).toBe(false); | ||
}); | ||
|
||
it.concurrent("should return true when input character is a letter", () => { | ||
expect(isLetter("A")).toBe(true); | ||
expect(isLetter("Z")).toBe(true); | ||
}); | ||
}); | ||
|
||
describe("stringUtils.isLetterOrDigit", () => { | ||
it.concurrent("should return false when input character is not a letter, nor a digit", () => { | ||
expect(isLetterOrDigit("")).toBe(false); | ||
expect(isLetterOrDigit(" ")).toBe(false); | ||
expect(isLetterOrDigit("|")).toBe(false); | ||
}); | ||
|
||
it.concurrent("should return true when input character is a letter or a digit", () => { | ||
expect(isLetterOrDigit("B")).toBe(true); | ||
expect(isLetterOrDigit("D")).toBe(true); | ||
expect(isLetterOrDigit("1")).toBe(true); | ||
expect(isLetterOrDigit("3")).toBe(true); | ||
}); | ||
}); | ||
|
||
describe("stringUtils.shortify", () => { | ||
it.concurrent("should return the same string when it is not too long", () => { | ||
expect(shortify("", 20)).toBe(""); | ||
expect(shortify(" ", 20)).toBe(" "); | ||
expect(shortify("Hello World!", 20)).toBe("Hello World!"); | ||
}); | ||
|
||
it.concurrent("should return the shortified string when it is too long", () => { | ||
expect(shortify("", -1)).toBe("…"); | ||
expect(shortify(" ", 2)).toBe(" …"); | ||
expect(shortify("Hello World!", 10)).toBe("Hello Wor…"); | ||
}); | ||
}); | ||
|
||
describe("stringUtils.slugify", () => { | ||
it.concurrent("should return an empty string when it is empty or undefined", () => { | ||
expect(slugify(undefined)).toBe(""); | ||
expect(slugify("")).toBe(""); | ||
expect(slugify(" ")).toBe(""); | ||
}); | ||
|
||
it.concurrent( | ||
"should separate the input string by non-alphanumeric characters, join them using hyphens (-), remove accents and return a lowercased slug", | ||
() => { | ||
expect(slugify("arc-en-ciel")).toBe("arc-en-ciel"); | ||
expect(slugify("Héllo Wôrld!")).toBe("hello-world"); | ||
} | ||
); | ||
}); | ||
|
||
describe("stringUtils.unaccent", () => { | ||
it.concurrent("should return the same string when it contains no supported accents", () => { | ||
expect(unaccent("")).toBe(""); | ||
expect(unaccent(" ")).toBe(" "); | ||
expect(unaccent("Hello World!")).toBe("Hello World!"); | ||
}); | ||
|
||
it.concurrent("should return the string without accents when it contains supported accents", () => { | ||
expect(unaccent("français")).toBe("francais"); | ||
expect(unaccent(" Noël ")).toBe(" Noel "); | ||
expect(unaccent("Héllo Wôrld!")).toBe("Hello World!"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,22 @@ | ||
export function orderBy<T>(items: T[], key?: keyof T): T[] { | ||
return key ? [...items].sort((a, b) => (a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0)) : [...items].sort(); | ||
function compare<T>(a: T, b: T, weight: number): number { | ||
if (typeof a === "undefined" || a === null || typeof b === "undefined" || b === null) { | ||
if ((a ?? null) === null && (b ?? null) !== null) { | ||
return -weight; | ||
} else if ((a ?? null) !== null && (b ?? null) === null) { | ||
return weight; | ||
} | ||
return 0; | ||
} | ||
return a < b ? -weight : a > b ? weight : 0; | ||
} | ||
export function orderBy<T>(items: T[], key?: keyof T, isDescending?: boolean): T[] { | ||
const weight = isDescending ? -1 : 1; | ||
if (key) { | ||
return [...items].sort((a, b) => compare(a[key], b[key], weight)); | ||
} | ||
return [...items].sort((a, b) => compare(a, b, weight)); | ||
} | ||
|
||
export function orderByDescending<T>(items: T[], key?: keyof T) { | ||
return orderBy(items, key, true); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
export function isMobile(): boolean { | ||
let check = false; | ||
(function (a) { | ||
if ( | ||
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test( | ||
a | ||
) || | ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test( | ||
a.substr(0, 4) | ||
) | ||
) | ||
check = true; | ||
// @ts-ignore | ||
})(navigator.userAgent || navigator.vendor || window.opera); | ||
return check; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.