Merge remote-tracking branch 'origin/main' into slash
This commit is contained in:
commit
4d8eabcc2c
18 changed files with 784 additions and 21 deletions
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: "[Bug] "
|
||||||
|
labels: "bug \U0001F41B"
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**What's the bug?**
|
||||||
|
<!-- Please tell us about the bug as short and easy to understand. -->
|
||||||
|
|
||||||
|
**How do we reproduce it?**
|
||||||
|
<!-- Do:
|
||||||
|
1. Use `something function` in `messageCreate` event
|
||||||
|
2. Make a message
|
||||||
|
3. Bamm!
|
||||||
|
|
||||||
|
Don't:
|
||||||
|
1. Run code
|
||||||
|
2. Error!
|
||||||
|
-->
|
||||||
|
|
||||||
|
**What should have happened?**
|
||||||
|
<!-- We might not know what you were expecting. Please tell us. -->
|
||||||
|
|
||||||
|
**What is actually happening?**
|
||||||
|
<!-- Please tell us the result of the code. -->
|
||||||
|
|
||||||
|
**What versions you're using?**
|
||||||
|
- OS: <!-- [e.g. macOS 11.1 Big Sur] -->
|
||||||
|
- Deno: <!-- [e.g. Deno 1.6.1] -->
|
||||||
|
- Harmony: <!-- [e.g. Harmony 0.9.0] -->
|
||||||
|
|
||||||
|
**Do you have anything to tell us more about the bug?**
|
||||||
|
<!-- If you do, please tell us more in here. -->
|
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: "[Feature Request] "
|
||||||
|
labels: enhancement ✨
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**What do you want to request?**
|
||||||
|
<!-- Please tell us about your request as short and easy to understand. -->
|
||||||
|
|
||||||
|
<!-- !!REMOVE THIS TAG IF YOU ALREADY HAVE(..or thought about) SOME SOLUTIONS!!
|
||||||
|
**Do you have any solutions?**
|
||||||
|
If you have, please tell us so we can add(or at least think about) your solution!
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Do you have anything to tell us about your request?**
|
||||||
|
<!-- If you do, please tell us more in here. -->
|
11
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
11
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
name: Question
|
||||||
|
about: Question about this project
|
||||||
|
title: "[Question] "
|
||||||
|
labels: question ❓
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**What question do you have?**
|
||||||
|
<!-- Please tell us your question as short and easy to understand. -->
|
34
README.md
34
README.md
|
@ -101,6 +101,40 @@ client.commands.add(PingCommand)
|
||||||
client.connect('super secret token comes here', Intents.All)
|
client.connect('super secret token comes here', Intents.All)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Or with Decorators!
|
||||||
|
```ts
|
||||||
|
import {
|
||||||
|
Client,
|
||||||
|
event,
|
||||||
|
Intents,
|
||||||
|
command,
|
||||||
|
CommandContext,
|
||||||
|
} from 'https://deno.land/x/harmony/mod.ts'
|
||||||
|
|
||||||
|
class MyClient extends CommandClient {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
prefix: ['!', '!!'],
|
||||||
|
caseSensitive: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@event()
|
||||||
|
ready(): void {
|
||||||
|
console.log(`Logged in as ${this.user?.tag}!`)
|
||||||
|
}
|
||||||
|
|
||||||
|
@command({ aliases: 'pong' })
|
||||||
|
Ping(ctx: CommandContext): void {
|
||||||
|
ctx.message.reply('Pong!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to gateway
|
||||||
|
// Replace with your bot's token and intents (Intents.All, Intents.None, Intents.Presence, Intents.GuildMembers)
|
||||||
|
new MyClient().connect('super secret token comes here', Intents.All)
|
||||||
|
```
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
|
|
||||||
Documentation is available for `main` (branch) and `stable` (release).
|
Documentation is available for `main` (branch) and `stable` (release).
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "harmony",
|
"name": "harmony",
|
||||||
"version": "0.9.0",
|
"version": "0.9.2",
|
||||||
"description": "Discord Deno API that is easy to use.",
|
"description": "Discord Deno API that is easy to use.",
|
||||||
"main": "mod.ts",
|
"main": "mod.ts",
|
||||||
"repository": "https://github.com/harmony-org/harmony.git",
|
"repository": "https://github.com/harmony-org/harmony.git",
|
||||||
|
|
|
@ -42,7 +42,7 @@ export class BaseManager<T, T2> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets an Array of values from Cache */
|
/** Gets an Array of values from Cache */
|
||||||
async array(): Promise<undefined | T2[]> {
|
async array(): Promise<T2[]> {
|
||||||
let arr = await (this.client.cache.array(this.cacheName) as T[])
|
let arr = await (this.client.cache.array(this.cacheName) as T[])
|
||||||
if (arr === undefined) arr = []
|
if (arr === undefined) arr = []
|
||||||
return arr.map((e) => new this.DataType(this.client, e)) as any
|
return arr.map((e) => new this.DataType(this.client, e)) as any
|
||||||
|
|
|
@ -25,7 +25,7 @@ export class ChannelsManager extends BaseManager<ChannelPayload, Channel> {
|
||||||
return res as any
|
return res as any
|
||||||
}
|
}
|
||||||
|
|
||||||
async array(): Promise<undefined | Channel[]> {
|
async array(): Promise<Channel[]> {
|
||||||
const arr = await (this.client.cache.array(
|
const arr = await (this.client.cache.array(
|
||||||
this.cacheName
|
this.cacheName
|
||||||
) as ChannelPayload[])
|
) as ChannelPayload[])
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class GuildVoiceStatesManager extends BaseManager<
|
||||||
return new VoiceState(this.client, raw, {
|
return new VoiceState(this.client, raw, {
|
||||||
user: ((await this.client.users.get(raw.user_id)) as unknown) as User,
|
user: ((await this.client.users.get(raw.user_id)) as unknown) as User,
|
||||||
channel:
|
channel:
|
||||||
raw.channel_id == null
|
raw.channel_id === null
|
||||||
? null
|
? null
|
||||||
: (((await this.client.channels.get<VoiceChannel>(
|
: (((await this.client.channels.get<VoiceChannel>(
|
||||||
raw.channel_id
|
raw.channel_id
|
||||||
|
@ -40,6 +40,37 @@ export class GuildVoiceStatesManager extends BaseManager<
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async array(): Promise<VoiceState[]> {
|
||||||
|
let arr = await (this.client.cache.array(
|
||||||
|
this.cacheName
|
||||||
|
) as VoiceStatePayload[])
|
||||||
|
if (arr === undefined) arr = []
|
||||||
|
|
||||||
|
return await Promise.all(
|
||||||
|
arr.map(async (raw) => {
|
||||||
|
const guild =
|
||||||
|
raw.guild_id === undefined
|
||||||
|
? undefined
|
||||||
|
: await this.client.guilds.get(raw.guild_id)
|
||||||
|
|
||||||
|
return new VoiceState(this.client, raw, {
|
||||||
|
user: ((await this.client.users.get(raw.user_id)) as unknown) as User,
|
||||||
|
channel:
|
||||||
|
raw.channel_id === null
|
||||||
|
? null
|
||||||
|
: (((await this.client.channels.get<VoiceChannel>(
|
||||||
|
raw.channel_id
|
||||||
|
)) as unknown) as VoiceChannel),
|
||||||
|
guild,
|
||||||
|
member:
|
||||||
|
guild === undefined
|
||||||
|
? undefined
|
||||||
|
: await guild.members.get(raw.user_id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async fromPayload(d: VoiceStatePayload[]): Promise<void> {
|
async fromPayload(d: VoiceStatePayload[]): Promise<void> {
|
||||||
for (const data of d) {
|
for (const data of d) {
|
||||||
await this.set(data.user_id, data)
|
await this.set(data.user_id, data)
|
||||||
|
|
|
@ -37,6 +37,27 @@ export class MembersManager extends BaseManager<MemberPayload, Member> {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async array(): Promise<Member[]> {
|
||||||
|
let arr = await (this.client.cache.array(this.cacheName) as MemberPayload[])
|
||||||
|
if (arr === undefined) arr = []
|
||||||
|
|
||||||
|
return await Promise.all(
|
||||||
|
arr.map(async (raw) => {
|
||||||
|
const user = new User(this.client, raw.user)
|
||||||
|
const roles = await this.guild.roles.array()
|
||||||
|
let permissions = new Permissions(Permissions.DEFAULT)
|
||||||
|
if (roles !== undefined) {
|
||||||
|
const mRoles = roles.filter(
|
||||||
|
(r) =>
|
||||||
|
(raw.roles.includes(r.id) as boolean) || r.id === this.guild.id
|
||||||
|
)
|
||||||
|
permissions = new Permissions(mRoles.map((r) => r.permissions))
|
||||||
|
}
|
||||||
|
return new Member(this.client, raw, user, this.guild, permissions)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async fetch(id: string): Promise<Member> {
|
async fetch(id: string): Promise<Member> {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
this.client.rest
|
this.client.rest
|
||||||
|
|
|
@ -37,6 +37,20 @@ export class MessageReactionsManager extends BaseManager<
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async array(): Promise<MessageReaction[]> {
|
||||||
|
let arr = await (this.client.cache.array(this.cacheName) as Reaction[])
|
||||||
|
if (arr === undefined) arr = []
|
||||||
|
|
||||||
|
return await Promise.all(
|
||||||
|
arr.map(async (raw) => {
|
||||||
|
let emoji = await this.client.emojis.get(raw.emoji.id)
|
||||||
|
if (emoji === undefined) emoji = new Emoji(this.client, raw.emoji)
|
||||||
|
|
||||||
|
return new MessageReaction(this.client, raw, this.message, emoji)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async flush(): Promise<any> {
|
async flush(): Promise<any> {
|
||||||
await this.client.cache.deleteCache(`reaction_users:${this.message.id}`)
|
await this.client.cache.deleteCache(`reaction_users:${this.message.id}`)
|
||||||
return this.client.cache.deleteCache(this.cacheName)
|
return this.client.cache.deleteCache(this.cacheName)
|
||||||
|
|
|
@ -44,6 +44,42 @@ export class MessagesManager extends BaseManager<MessagePayload, Message> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async array(): Promise<Message[]> {
|
||||||
|
let arr = await (this.client.cache.array(
|
||||||
|
this.cacheName
|
||||||
|
) as MessagePayload[])
|
||||||
|
if (arr === undefined) arr = []
|
||||||
|
|
||||||
|
const result: Message[] = []
|
||||||
|
await Promise.all(
|
||||||
|
arr.map(async (raw) => {
|
||||||
|
if (raw.author === undefined) return
|
||||||
|
|
||||||
|
let channel = await this.client.channels.get(raw.channel_id)
|
||||||
|
if (channel === undefined)
|
||||||
|
channel = await this.client.channels.fetch(raw.channel_id)
|
||||||
|
if (channel === undefined) return
|
||||||
|
|
||||||
|
let author = ((await this.client.users.get(
|
||||||
|
raw.author.id
|
||||||
|
)) as unknown) as User
|
||||||
|
|
||||||
|
if (author === undefined) author = new User(this.client, raw.author)
|
||||||
|
|
||||||
|
const res = new Message(
|
||||||
|
this.client,
|
||||||
|
raw,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||||
|
channel as TextChannel,
|
||||||
|
author
|
||||||
|
)
|
||||||
|
await res.mentions.fromPayload(raw)
|
||||||
|
result.push(res)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
async fetch(id: string): Promise<Message> {
|
async fetch(id: string): Promise<Message> {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
this.client.rest
|
this.client.rest
|
||||||
|
|
|
@ -27,6 +27,25 @@ export class GuildPresencesManager extends BaseManager<
|
||||||
return presence
|
return presence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async array(): Promise<Presence[]> {
|
||||||
|
let arr = await (this.client.cache.array(
|
||||||
|
this.cacheName
|
||||||
|
) as PresenceUpdatePayload[])
|
||||||
|
if (arr === undefined) arr = []
|
||||||
|
|
||||||
|
const result: Presence[] = []
|
||||||
|
await Promise.all(
|
||||||
|
arr.map(async (raw) => {
|
||||||
|
let user = await this.client.users.get(raw.user.id)
|
||||||
|
if (user === undefined) user = new User(this.client, raw.user)
|
||||||
|
const guild = await this.client.guilds.get(raw.guild_id)
|
||||||
|
if (guild === undefined) return
|
||||||
|
result.push(new Presence(this.client, raw, user, guild))
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
async fromPayload(
|
async fromPayload(
|
||||||
data: PresenceUpdatePayload[]
|
data: PresenceUpdatePayload[]
|
||||||
): Promise<GuildPresencesManager> {
|
): Promise<GuildPresencesManager> {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { MessageMentions } from './messageMentions.ts'
|
||||||
import { TextChannel } from './textChannel.ts'
|
import { TextChannel } from './textChannel.ts'
|
||||||
import { Guild } from './guild.ts'
|
import { Guild } from './guild.ts'
|
||||||
import { MessageReactionsManager } from '../managers/messageReactions.ts'
|
import { MessageReactionsManager } from '../managers/messageReactions.ts'
|
||||||
|
import { MessageSticker } from './messageSticker.ts'
|
||||||
|
|
||||||
type AllMessageOptions = MessageOption | Embed
|
type AllMessageOptions = MessageOption | Embed
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ export class Message extends Base {
|
||||||
application?: MessageApplication
|
application?: MessageApplication
|
||||||
messageReference?: MessageReference
|
messageReference?: MessageReference
|
||||||
flags?: number
|
flags?: number
|
||||||
|
stickers?: MessageSticker[]
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
client: Client,
|
client: Client,
|
||||||
|
@ -72,6 +74,12 @@ export class Message extends Base {
|
||||||
this.messageReference = data.message_reference
|
this.messageReference = data.message_reference
|
||||||
this.flags = data.flags
|
this.flags = data.flags
|
||||||
this.channel = channel
|
this.channel = channel
|
||||||
|
this.stickers =
|
||||||
|
data.stickers !== undefined
|
||||||
|
? data.stickers.map(
|
||||||
|
(payload) => new MessageSticker(this.client, payload)
|
||||||
|
)
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
readFromData(data: MessagePayload): void {
|
readFromData(data: MessagePayload): void {
|
||||||
|
@ -91,6 +99,12 @@ export class Message extends Base {
|
||||||
this.application = data.application ?? this.application
|
this.application = data.application ?? this.application
|
||||||
this.messageReference = data.message_reference ?? this.messageReference
|
this.messageReference = data.message_reference ?? this.messageReference
|
||||||
this.flags = data.flags ?? this.flags
|
this.flags = data.flags ?? this.flags
|
||||||
|
this.stickers =
|
||||||
|
data.stickers !== undefined
|
||||||
|
? data.stickers.map(
|
||||||
|
(payload) => new MessageSticker(this.client, payload)
|
||||||
|
)
|
||||||
|
: this.stickers
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Edits this message. */
|
/** Edits this message. */
|
||||||
|
|
43
src/structures/messageSticker.ts
Normal file
43
src/structures/messageSticker.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { Client } from '../models/client.ts'
|
||||||
|
import {
|
||||||
|
MessageStickerFormatTypes,
|
||||||
|
MessageStickerPayload
|
||||||
|
} from '../types/channel.ts'
|
||||||
|
import { Base } from './base.ts'
|
||||||
|
|
||||||
|
export class MessageSticker extends Base {
|
||||||
|
id: string
|
||||||
|
packID: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
tags?: string[]
|
||||||
|
asset: string
|
||||||
|
previewAsset: string | null
|
||||||
|
formatType: MessageStickerFormatTypes
|
||||||
|
|
||||||
|
constructor(client: Client, data: MessageStickerPayload) {
|
||||||
|
super(client)
|
||||||
|
|
||||||
|
this.id = data.id
|
||||||
|
this.packID = data.pack_id
|
||||||
|
this.name = data.name
|
||||||
|
this.description = data.description
|
||||||
|
this.tags = data.tags !== undefined ? data.tags.split(', ') : undefined
|
||||||
|
this.asset = data.asset
|
||||||
|
this.previewAsset = data.preview_asset
|
||||||
|
this.formatType = data.format_type
|
||||||
|
}
|
||||||
|
|
||||||
|
readFromData(data: MessageStickerPayload): void {
|
||||||
|
this.id = data.id ?? this.id
|
||||||
|
this.packID = data.pack_id ?? this.packID
|
||||||
|
this.name = data.name ?? this.name
|
||||||
|
this.description = data.description ?? this.description
|
||||||
|
this.tags = data.tags !== undefined ? data.tags.split(', ') : this.tags
|
||||||
|
this.asset = data.asset ?? this.asset
|
||||||
|
this.previewAsset = data.preview_asset ?? this.previewAsset
|
||||||
|
this.formatType = data.format_type ?? this.formatType
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Make asset url function when it's available
|
||||||
|
}
|
|
@ -14,9 +14,9 @@ import {
|
||||||
import { TOKEN } from './config.ts'
|
import { TOKEN } from './config.ts'
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
clientProperties: {
|
// clientProperties: {
|
||||||
browser: 'Discord iOS'
|
// browser: 'Discord iOS'
|
||||||
}
|
// }
|
||||||
// bot: false,
|
// bot: false,
|
||||||
// cache: new RedisCacheAdapter({
|
// cache: new RedisCacheAdapter({
|
||||||
// hostname: '127.0.0.1',
|
// hostname: '127.0.0.1',
|
||||||
|
@ -47,14 +47,21 @@ client.on('channelUpdate', (b: EveryChannelTypes, a: EveryChannelTypes) => {
|
||||||
|
|
||||||
client.on('messageCreate', async (msg: Message) => {
|
client.on('messageCreate', async (msg: Message) => {
|
||||||
if (msg.author.bot === true) return
|
if (msg.author.bot === true) return
|
||||||
console.log(`${msg.author.tag}: ${msg.content}`)
|
if (msg.stickers !== undefined) {
|
||||||
|
console.log(
|
||||||
|
`${msg.author.tag}: (Sticker)${msg.stickers.map(
|
||||||
|
(sticker) => `Name: ${sticker.name}, Tags: ${sticker.tags}`
|
||||||
|
)}`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
console.log(`${msg.author.tag}: ${msg.content}`)
|
||||||
|
}
|
||||||
if (msg.content === '!ping') {
|
if (msg.content === '!ping') {
|
||||||
msg.reply(`Pong! Ping: ${client.ping}ms`)
|
msg.reply(`Pong! Ping: ${client.ping}ms`)
|
||||||
} else if (msg.content === '!members') {
|
} else if (msg.content === '!members') {
|
||||||
const col = await msg.guild?.members.collection()
|
const col = await msg.guild?.members.array()
|
||||||
const data = col
|
const data = col
|
||||||
?.array()
|
?.map((c: Member, i: number) => {
|
||||||
.map((c: Member, i: number) => {
|
|
||||||
return `${i + 1}. ${c.user.tag}`
|
return `${i + 1}. ${c.user.tag}`
|
||||||
})
|
})
|
||||||
.join('\n') as string
|
.join('\n') as string
|
||||||
|
|
|
@ -96,6 +96,7 @@ export interface MessagePayload {
|
||||||
application?: MessageApplication
|
application?: MessageApplication
|
||||||
message_reference?: MessageReference
|
message_reference?: MessageReference
|
||||||
flags?: number
|
flags?: number
|
||||||
|
stickers?: MessageStickerPayload[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageOption {
|
export interface MessageOption {
|
||||||
|
@ -256,3 +257,20 @@ export interface FollowedChannel {
|
||||||
channel_id: string
|
channel_id: string
|
||||||
webhook_id: string
|
webhook_id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum MessageStickerFormatTypes {
|
||||||
|
PNG = 1,
|
||||||
|
APNG = 2,
|
||||||
|
LOTTIE = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessageStickerPayload {
|
||||||
|
id: string
|
||||||
|
pack_id: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
tags?: string
|
||||||
|
asset: string
|
||||||
|
preview_asset: string | null
|
||||||
|
format_type: MessageStickerFormatTypes
|
||||||
|
}
|
||||||
|
|
|
@ -10,20 +10,37 @@ export class Collection<K = string, V = any> extends Map<K, V> {
|
||||||
return [...this.values()]
|
return [...this.values()]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get first value in Collection */
|
/** Get first value(s) in Collection */
|
||||||
first(): V {
|
first(): V | undefined;
|
||||||
return this.values().next().value
|
first(amount: number): V[];
|
||||||
|
first(amount?: number): V | V[] | undefined {
|
||||||
|
if (typeof amount === 'undefined') return this.values().next().value
|
||||||
|
if (amount < 0) return this.last(amount * -1)
|
||||||
|
amount = Math.min(this.size, amount)
|
||||||
|
const iter = this.values()
|
||||||
|
return Array.from({ length: amount }, (): V => iter.next().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get last value in Collection */
|
/** Get last value(s) in Collection */
|
||||||
last(): V {
|
last(): V | undefined;
|
||||||
return [...this.values()][this.size - 1]
|
last(amount: number): V[];
|
||||||
|
last(amount?: number): V | V[] | undefined {
|
||||||
|
const arr = this.array()
|
||||||
|
if (typeof amount === 'undefined') return arr[arr.length - 1]
|
||||||
|
if (amount < 0) return this.first(amount * -1)
|
||||||
|
if (!amount) return [] // eslint-disable-line
|
||||||
|
return arr.slice(-amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a random value from Collection */
|
/** Get random value(s) from Collection */
|
||||||
random(): V {
|
random(): V;
|
||||||
const arr = [...this.values()]
|
random(amount: number): V[];
|
||||||
return arr[Math.floor(Math.random() * arr.length)]
|
random(amount?: number): V | V[] {
|
||||||
|
let arr = this.array()
|
||||||
|
if (typeof amount === 'undefined') return arr[Math.floor(Math.random() * arr.length)]
|
||||||
|
if (arr.length === 0 || !amount) return [] // eslint-disable-line
|
||||||
|
arr = arr.slice()
|
||||||
|
return Array.from({ length: amount }, (): V => arr.splice(Math.floor(Math.random() * arr.length), 1)[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Find a value from Collection using callback */
|
/** Find a value from Collection using callback */
|
||||||
|
|
443
src/utils/colorutil.ts
Normal file
443
src/utils/colorutil.ts
Normal file
|
@ -0,0 +1,443 @@
|
||||||
|
export interface Colors {
|
||||||
|
|
||||||
|
// Custom list
|
||||||
|
DEFAULT: number;
|
||||||
|
WHITE: number;
|
||||||
|
AQUA: number;
|
||||||
|
GREEN: number;
|
||||||
|
BLUE: number;
|
||||||
|
YELLOW: number;
|
||||||
|
PURPLE: number;
|
||||||
|
LUMINOUS_VIVID_PINK: number;
|
||||||
|
GOLD: number;
|
||||||
|
ORANGE: number;
|
||||||
|
RED: number;
|
||||||
|
GREY: number;
|
||||||
|
NAVY: number;
|
||||||
|
DARK_AQUA: number;
|
||||||
|
DARK_GREEN: number;
|
||||||
|
DARK_BLUE: number;
|
||||||
|
DARK_PURPLE: number;
|
||||||
|
DARK_VIVID_PINK: number;
|
||||||
|
DARK_GOLD: number;
|
||||||
|
DARK_ORANGE: number;
|
||||||
|
DARK_RED: number;
|
||||||
|
DARK_GREY: number;
|
||||||
|
DARKER_GREY: number;
|
||||||
|
LIGHT_GREY: number;
|
||||||
|
DARK_NAVY: number;
|
||||||
|
BLURPLE: number;
|
||||||
|
DARK_BLURPLE: number;
|
||||||
|
GREYPLE: number;
|
||||||
|
DARK_BUT_NOT_BLACK: number;
|
||||||
|
NOT_QUITE_BLACK: number;
|
||||||
|
|
||||||
|
// css color list
|
||||||
|
aliceblue: number;
|
||||||
|
antiquewhite: number;
|
||||||
|
aqua: number;
|
||||||
|
aquamarine: number;
|
||||||
|
azure: number;
|
||||||
|
beige: number;
|
||||||
|
bisque: number;
|
||||||
|
black: number;
|
||||||
|
blanchedalmond: number;
|
||||||
|
blue: number;
|
||||||
|
blueviolet: number;
|
||||||
|
brown: number;
|
||||||
|
burlywood: number;
|
||||||
|
cadetblue: number;
|
||||||
|
chartreuse: number;
|
||||||
|
chocolate: number;
|
||||||
|
coral: number;
|
||||||
|
cornflowerblue: number;
|
||||||
|
cornsilk: number;
|
||||||
|
crimson: number;
|
||||||
|
cyan: number;
|
||||||
|
darkblue: number;
|
||||||
|
darkcyan: number;
|
||||||
|
darkgoldenrod: number;
|
||||||
|
darkgray: number;
|
||||||
|
darkgreen: number;
|
||||||
|
darkgrey: number;
|
||||||
|
darkkhaki: number;
|
||||||
|
darkmagenta: number;
|
||||||
|
darkolivegreen: number;
|
||||||
|
darkorange: number;
|
||||||
|
darkorchid: number;
|
||||||
|
darkred: number;
|
||||||
|
darksalmon: number;
|
||||||
|
darkseagreen: number;
|
||||||
|
darkslateblue: number;
|
||||||
|
darkslategray: number;
|
||||||
|
darkslategrey: number;
|
||||||
|
darkturquoise: number;
|
||||||
|
darkviolet: number;
|
||||||
|
deeppink: number;
|
||||||
|
deepskyblue: number;
|
||||||
|
dimgray: number;
|
||||||
|
dimgrey: number;
|
||||||
|
dodgerblue: number;
|
||||||
|
firebrick: number;
|
||||||
|
floralwhite: number;
|
||||||
|
forestgreen: number;
|
||||||
|
fuchsia: number;
|
||||||
|
gainsboro: number;
|
||||||
|
ghostwhite: number;
|
||||||
|
goldenrod: number;
|
||||||
|
gold: number;
|
||||||
|
gray: number;
|
||||||
|
green: number;
|
||||||
|
greenyellow: number;
|
||||||
|
grey: number;
|
||||||
|
honeydew: number;
|
||||||
|
hotpink: number;
|
||||||
|
indianred: number;
|
||||||
|
indigo: number;
|
||||||
|
ivory: number;
|
||||||
|
khaki: number;
|
||||||
|
lavenderblush: number;
|
||||||
|
lavender: number;
|
||||||
|
lawngreen: number;
|
||||||
|
lemonchiffon: number;
|
||||||
|
lightblue: number;
|
||||||
|
lightcoral: number;
|
||||||
|
lightcyan: number;
|
||||||
|
lightgoldenrodyellow: number;
|
||||||
|
lightgray: number;
|
||||||
|
lightgreen: number;
|
||||||
|
lightgrey: number;
|
||||||
|
lightpink: number;
|
||||||
|
lightsalmon: number;
|
||||||
|
lightseagreen: number;
|
||||||
|
lightskyblue: number;
|
||||||
|
lightslategray: number;
|
||||||
|
lightslategrey: number;
|
||||||
|
lightsteelblue: number;
|
||||||
|
lightyellow: number;
|
||||||
|
lime: number;
|
||||||
|
limegreen: number;
|
||||||
|
linen: number;
|
||||||
|
magenta: number;
|
||||||
|
maroon: number;
|
||||||
|
mediumaquamarine: number;
|
||||||
|
mediumblue: number;
|
||||||
|
mediumorchid: number;
|
||||||
|
mediumpurple: number;
|
||||||
|
mediumseagreen: number;
|
||||||
|
mediumslateblue: number;
|
||||||
|
mediumspringgreen: number;
|
||||||
|
mediumturquoise: number;
|
||||||
|
mediumvioletred: number;
|
||||||
|
midnightblue: number;
|
||||||
|
mintcream: number;
|
||||||
|
mistyrose: number;
|
||||||
|
moccasin: number;
|
||||||
|
navajowhite: number;
|
||||||
|
navy: number;
|
||||||
|
oldlace: number;
|
||||||
|
olive: number;
|
||||||
|
olivedrab: number;
|
||||||
|
orange: number;
|
||||||
|
orangered: number;
|
||||||
|
orchid: number;
|
||||||
|
palegoldenrod: number;
|
||||||
|
palegreen: number;
|
||||||
|
paleturquoise: number;
|
||||||
|
palevioletred: number;
|
||||||
|
papayawhip: number;
|
||||||
|
peachpuff: number;
|
||||||
|
peru: number;
|
||||||
|
pink: number;
|
||||||
|
plum: number;
|
||||||
|
powderblue: number;
|
||||||
|
purple: number;
|
||||||
|
rebeccapurple: number;
|
||||||
|
red: number;
|
||||||
|
rosybrown: number;
|
||||||
|
royalblue: number;
|
||||||
|
saddlebrown: number;
|
||||||
|
salmon: number;
|
||||||
|
sandybrown: number;
|
||||||
|
seagreen: number;
|
||||||
|
seashell: number;
|
||||||
|
sienna: number;
|
||||||
|
silver: number;
|
||||||
|
skyblue: number;
|
||||||
|
slateblue: number;
|
||||||
|
slategray: number;
|
||||||
|
slategrey: number;
|
||||||
|
snow: number;
|
||||||
|
springgreen: number;
|
||||||
|
steelblue: number;
|
||||||
|
tan: number;
|
||||||
|
teal: number;
|
||||||
|
thistle: number;
|
||||||
|
tomato: number;
|
||||||
|
turquoise: number;
|
||||||
|
violet: number;
|
||||||
|
wheat: number;
|
||||||
|
white: number;
|
||||||
|
whitesmoke: number;
|
||||||
|
yellow: number;
|
||||||
|
yellowgreen: number
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
export class ColorUtil {
|
||||||
|
constructor() {
|
||||||
|
throw new Error(`The ${this.constructor.name} class may not be instantiated!`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes color int into hex code
|
||||||
|
* @param color The color as int
|
||||||
|
*/
|
||||||
|
static intToHex(color: number): string {
|
||||||
|
if (!ColorUtil.validateColor(color)) throw new Error('Invalid color')
|
||||||
|
return `#${color.toString(16)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates hex color
|
||||||
|
* @param color The color to validate
|
||||||
|
*/
|
||||||
|
static validateColor(color: number): boolean {
|
||||||
|
if (color < 0 || color > 0xffffff) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves RGB color array
|
||||||
|
* @param color RGB color array
|
||||||
|
*/
|
||||||
|
static resolveRGB(color: [number, number, number]): number {
|
||||||
|
return (color[0] << 16) + (color[1] << 8) + color[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves hex code
|
||||||
|
* @param hexcode The hex code
|
||||||
|
*/
|
||||||
|
static resolveHex(hexcode: string): number {
|
||||||
|
if (!ColorUtil.isHex(hexcode)) throw new Error('Invalid hex code')
|
||||||
|
return parseInt(hexcode.replace('#', ''), 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates hex code
|
||||||
|
* @param hexcode The hex code
|
||||||
|
*/
|
||||||
|
static isHex(hexcode: string): boolean {
|
||||||
|
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(hexcode)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns random hex code */
|
||||||
|
static randomHex(): string {
|
||||||
|
const code = `#${Math.floor(Math.random() * (0xffffff + 1)).toString(16)}`
|
||||||
|
if (!ColorUtil.isHex(code)) return '#000000'
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves color by name
|
||||||
|
* @param color The color name
|
||||||
|
*/
|
||||||
|
static resolveColor(color?: keyof Colors | 'RANDOM'): number {
|
||||||
|
if (!color) return 0 // eslint-disable-line
|
||||||
|
if (color === 'RANDOM') return Math.floor(Math.random() * (0xffffff + 1))
|
||||||
|
return ColorUtil.colorList[color]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Color list */
|
||||||
|
static get colorList(): Colors {
|
||||||
|
return {
|
||||||
|
// custom list
|
||||||
|
DEFAULT: 0x000000,
|
||||||
|
WHITE: 0xffffff,
|
||||||
|
AQUA: 0x1abc9c,
|
||||||
|
GREEN: 0x2ecc71,
|
||||||
|
BLUE: 0x3498db,
|
||||||
|
YELLOW: 0xffff00,
|
||||||
|
PURPLE: 0x9b59b6,
|
||||||
|
LUMINOUS_VIVID_PINK: 0xe91e63,
|
||||||
|
GOLD: 0xf1c40f,
|
||||||
|
ORANGE: 0xe67e22,
|
||||||
|
RED: 0xe74c3c,
|
||||||
|
GREY: 0x95a5a6,
|
||||||
|
NAVY: 0x34495e,
|
||||||
|
DARK_AQUA: 0x11806a,
|
||||||
|
DARK_GREEN: 0x1f8b4c,
|
||||||
|
DARK_BLUE: 0x206694,
|
||||||
|
DARK_PURPLE: 0x71368a,
|
||||||
|
DARK_VIVID_PINK: 0xad1457,
|
||||||
|
DARK_GOLD: 0xc27c0e,
|
||||||
|
DARK_ORANGE: 0xa84300,
|
||||||
|
DARK_RED: 0x992d22,
|
||||||
|
DARK_GREY: 0x979c9f,
|
||||||
|
DARKER_GREY: 0x7f8c8d,
|
||||||
|
LIGHT_GREY: 0xbcc0c0,
|
||||||
|
DARK_NAVY: 0x2c3e50,
|
||||||
|
BLURPLE: 0x7289da,
|
||||||
|
DARK_BLURPLE: 0x4d5e94,
|
||||||
|
GREYPLE: 0x99aab5,
|
||||||
|
DARK_BUT_NOT_BLACK: 0x2c2f33,
|
||||||
|
NOT_QUITE_BLACK: 0x23272a,
|
||||||
|
|
||||||
|
// css color list
|
||||||
|
aliceblue: 0xf0f8ff,
|
||||||
|
antiquewhite: 0xfaebd7,
|
||||||
|
aqua: 0x00ffff,
|
||||||
|
aquamarine: 0x7fffd4,
|
||||||
|
azure: 0xf0ffff,
|
||||||
|
beige: 0xf5f5dc,
|
||||||
|
bisque: 0xffe4c4,
|
||||||
|
black: 0x000000,
|
||||||
|
blanchedalmond: 0xffebcd,
|
||||||
|
blue: 0x0000ff,
|
||||||
|
blueviolet: 0x8a2be2,
|
||||||
|
brown: 0xa52a2a,
|
||||||
|
burlywood: 0xdeb887,
|
||||||
|
cadetblue: 0x5f9ea0,
|
||||||
|
chartreuse: 0x7fff00,
|
||||||
|
chocolate: 0xd2691e,
|
||||||
|
coral: 0xff7f50,
|
||||||
|
cornflowerblue: 0x6495ed,
|
||||||
|
cornsilk: 0xfff8dc,
|
||||||
|
crimson: 0xdc143c,
|
||||||
|
cyan: 0x00ffff,
|
||||||
|
darkblue: 0x00008b,
|
||||||
|
darkcyan: 0x008b8b,
|
||||||
|
darkgoldenrod: 0xb8860b,
|
||||||
|
darkgray: 0xa9a9a9,
|
||||||
|
darkgreen: 0x006400,
|
||||||
|
darkgrey: 0xa9a9a9,
|
||||||
|
darkkhaki: 0xbdb76b,
|
||||||
|
darkmagenta: 0x8b008b,
|
||||||
|
darkolivegreen: 0x556b2f,
|
||||||
|
darkorange: 0xff8c00,
|
||||||
|
darkorchid: 0x9932cc,
|
||||||
|
darkred: 0x8b0000,
|
||||||
|
darksalmon: 0xe9967a,
|
||||||
|
darkseagreen: 0x8fbc8f,
|
||||||
|
darkslateblue: 0x483d8b,
|
||||||
|
darkslategray: 0x2f4f4f,
|
||||||
|
darkslategrey: 0x2f4f4f,
|
||||||
|
darkturquoise: 0x00ced1,
|
||||||
|
darkviolet: 0x9400d3,
|
||||||
|
deeppink: 0xff1493,
|
||||||
|
deepskyblue: 0x00bfff,
|
||||||
|
dimgray: 0x696969,
|
||||||
|
dimgrey: 0x696969,
|
||||||
|
dodgerblue: 0x1e90ff,
|
||||||
|
firebrick: 0xb22222,
|
||||||
|
floralwhite: 0xfffaf0,
|
||||||
|
forestgreen: 0x228b22,
|
||||||
|
fuchsia: 0xff00ff,
|
||||||
|
gainsboro: 0xdcdcdc,
|
||||||
|
ghostwhite: 0xf8f8ff,
|
||||||
|
goldenrod: 0xdaa520,
|
||||||
|
gold: 0xffd700,
|
||||||
|
gray: 0x808080,
|
||||||
|
green: 0x008000,
|
||||||
|
greenyellow: 0xadff2f,
|
||||||
|
grey: 0x808080,
|
||||||
|
honeydew: 0xf0fff0,
|
||||||
|
hotpink: 0xff69b4,
|
||||||
|
indianred: 0xcd5c5c,
|
||||||
|
indigo: 0x4b0082,
|
||||||
|
ivory: 0xfffff0,
|
||||||
|
khaki: 0xf0e68c,
|
||||||
|
lavenderblush: 0xfff0f5,
|
||||||
|
lavender: 0xe6e6fa,
|
||||||
|
lawngreen: 0x7cfc00,
|
||||||
|
lemonchiffon: 0xfffacd,
|
||||||
|
lightblue: 0xadd8e6,
|
||||||
|
lightcoral: 0xf08080,
|
||||||
|
lightcyan: 0xe0ffff,
|
||||||
|
lightgoldenrodyellow: 0xfafad2,
|
||||||
|
lightgray: 0xd3d3d3,
|
||||||
|
lightgreen: 0x90ee90,
|
||||||
|
lightgrey: 0xd3d3d3,
|
||||||
|
lightpink: 0xffb6c1,
|
||||||
|
lightsalmon: 0xffa07a,
|
||||||
|
lightseagreen: 0x20b2aa,
|
||||||
|
lightskyblue: 0x87cefa,
|
||||||
|
lightslategray: 0x778899,
|
||||||
|
lightslategrey: 0x778899,
|
||||||
|
lightsteelblue: 0xb0c4de,
|
||||||
|
lightyellow: 0xffffe0,
|
||||||
|
lime: 0x00ff00,
|
||||||
|
limegreen: 0x32cd32,
|
||||||
|
linen: 0xfaf0e6,
|
||||||
|
magenta: 0xff00ff,
|
||||||
|
maroon: 0x800000,
|
||||||
|
mediumaquamarine: 0x66cdaa,
|
||||||
|
mediumblue: 0x0000cd,
|
||||||
|
mediumorchid: 0xba55d3,
|
||||||
|
mediumpurple: 0x9370db,
|
||||||
|
mediumseagreen: 0x3cb371,
|
||||||
|
mediumslateblue: 0x7b68ee,
|
||||||
|
mediumspringgreen: 0x00fa9a,
|
||||||
|
mediumturquoise: 0x48d1cc,
|
||||||
|
mediumvioletred: 0xc71585,
|
||||||
|
midnightblue: 0x191970,
|
||||||
|
mintcream: 0xf5fffa,
|
||||||
|
mistyrose: 0xffe4e1,
|
||||||
|
moccasin: 0xffe4b5,
|
||||||
|
navajowhite: 0xffdead,
|
||||||
|
navy: 0x000080,
|
||||||
|
oldlace: 0xfdf5e6,
|
||||||
|
olive: 0x808000,
|
||||||
|
olivedrab: 0x6b8e23,
|
||||||
|
orange: 0xffa500,
|
||||||
|
orangered: 0xff4500,
|
||||||
|
orchid: 0xda70d6,
|
||||||
|
palegoldenrod: 0xeee8aa,
|
||||||
|
palegreen: 0x98fb98,
|
||||||
|
paleturquoise: 0xafeeee,
|
||||||
|
palevioletred: 0xdb7093,
|
||||||
|
papayawhip: 0xffefd5,
|
||||||
|
peachpuff: 0xffdab9,
|
||||||
|
peru: 0xcd853f,
|
||||||
|
pink: 0xffc0cb,
|
||||||
|
plum: 0xdda0dd,
|
||||||
|
powderblue: 0xb0e0e6,
|
||||||
|
purple: 0x800080,
|
||||||
|
rebeccapurple: 0x663399,
|
||||||
|
red: 0xff0000,
|
||||||
|
rosybrown: 0xbc8f8f,
|
||||||
|
royalblue: 0x4169e1,
|
||||||
|
saddlebrown: 0x8b4513,
|
||||||
|
salmon: 0xfa8072,
|
||||||
|
sandybrown: 0xf4a460,
|
||||||
|
seagreen: 0x2e8b57,
|
||||||
|
seashell: 0xfff5ee,
|
||||||
|
sienna: 0xa0522d,
|
||||||
|
silver: 0xc0c0c0,
|
||||||
|
skyblue: 0x87ceeb,
|
||||||
|
slateblue: 0x6a5acd,
|
||||||
|
slategray: 0x708090,
|
||||||
|
slategrey: 0x708090,
|
||||||
|
snow: 0xfffafa,
|
||||||
|
springgreen: 0x00ff7f,
|
||||||
|
steelblue: 0x4682b4,
|
||||||
|
tan: 0xd2b48c,
|
||||||
|
teal: 0x008080,
|
||||||
|
thistle: 0xd8bfd8,
|
||||||
|
tomato: 0xff6347,
|
||||||
|
turquoise: 0x40e0d0,
|
||||||
|
violet: 0xee82ee,
|
||||||
|
wheat: 0xf5deb3,
|
||||||
|
white: 0xffffff,
|
||||||
|
whitesmoke: 0xf5f5f5,
|
||||||
|
yellow: 0xffff00,
|
||||||
|
yellowgreen: 0x9acd32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static toJSON(): Colors {
|
||||||
|
return ColorUtil.colorList
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue