fix: add base transformer

This commit is contained in:
Skillz
2022-12-27 12:38:30 -06:00
parent bd78eec931
commit 3bc40cd977
17 changed files with 532 additions and 7 deletions
+1
View File
@@ -24,6 +24,7 @@
"test:test-type": "tsc --project tsconfig.test.json"
},
"dependencies": {
"@discordeno/transformer": "18.0.0-alpha.1",
"dotenv": "^16.0.3"
},
"devDependencies": {
+60 -6
View File
@@ -1,6 +1,10 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import TRANSFORMERS from '@discordeno/transformer'
import type { BigString, Camelize, DiscordUser } from '@discordeno/types'
// TODO: make dynamic based on package.json file
const version = '18.0.0-alpha.1'
export function createRestManager (options: CreateRestManagerOptions): RestManager {
const rest: RestManager = {
token: options.token,
@@ -9,15 +13,49 @@ export function createRestManager (options: CreateRestManagerOptions): RestManag
routes: {
// User endpoints
user: (userId: BigString) => {
user (userId: BigString) {
return `/users/${userId}`
}
},
createRequest (options) {
const headers: Record<string, string> = {
'user-agent': `DiscordBot (https://github.com/discordeno/discordeno, v${version})`
}
if (!options.unauthorized) headers.authorization = `Bot ${rest.token}`
// SOMETIMES SPECIAL HEADERS (E.G. CUSTOM AUTHORIZATION) NEED TO BE USED
if (options.headers) {
for (const key in options.headers) {
headers[key.toLowerCase()] = options.headers[key]
}
}
// GET METHODS SHOULD NOT HAVE A BODY
if (options.method === 'GET') {
options.body = undefined
}
// IF A REASON IS PROVIDED ENCODE IT IN HEADERS
if (options.body?.reason) {
headers['X-Audit-Log-Reason'] = encodeURIComponent(
options.body.reason as string
)
options.body.reason = undefined
}
return {
headers,
body: (options.body?.file ?? JSON.stringify(options.body)) as
| FormData
| string,
method: options.method
}
},
async makeRequest (method, url) {
return await fetch(`${rest.baseUrl}/v${rest.version}/${url}`, {
method
}).then(async res => await res.json())
return await fetch(`${rest.baseUrl}/v${rest.version}/${url}`, rest.createRequest({ method, url })).then(async res => await res.json())
},
async get (url) {
@@ -25,8 +63,8 @@ export function createRestManager (options: CreateRestManagerOptions): RestManag
},
async getUser (id) {
// TODO: camelize
return await rest.get<DiscordUser>(rest.routes.user(id))
const result = await rest.get<DiscordUser>(rest.routes.user(id))
return TRANSFORMERS.user(result)
}
}
@@ -65,6 +103,8 @@ export interface RestManager {
/** A specific user route. */
user: (id: BigString) => string
}
/** Creates the request body and headers that are necessary to send a request. Will handle different types of methods and everything necessary for discord. */
createRequest: (options: CreateRequestBodyOptions) => RequestBody
/** Make a request to the api. */
makeRequest: <T = unknown>(method: RequestMethods, url: string) => Promise<T>
/** Make a get request to the api */
@@ -80,3 +120,17 @@ export interface RestManager {
export type RequestMethods = 'GET'
export type ApiVersions = 9 | 10
export interface CreateRequestBodyOptions {
headers?: Record<string, string>
method: RequestMethods
body?: Record<string, unknown>
unauthorized?: boolean
url?: string
}
export interface RequestBody {
headers: Record<string, string>
body: string | FormData
method: RequestMethods
}
+45
View File
@@ -0,0 +1,45 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { rest } from '../utils.js'
describe('[rest] manager', () => {
describe('Get a user from the api', () => {
it('With a valid user id', async () => {
const user = await rest.getUser('130136895395987456')
describe('User has correct shape and form', () => {
it('Has correct id', () => {
expect(user.id).to.be.equal('130136895395987456')
})
it('Has a valid username', () => {
expect(user.username.length).to.be.greaterThanOrEqual(1)
})
it('Has a valid discriminator', () => {
expect(user.discriminator.length).to.be.equal(4)
})
it('Has been camelized', () => {
const keys = Object.keys(user)
expect(keys.includes('mfa_enabled')).to.be.false
expect(keys.includes('accent_color')).to.be.false
expect(keys.includes('premium_type')).to.be.false
expect(keys.includes('public_flags')).to.be.false
expect(keys.includes('mfaEnabled')).to.be.true
expect(keys.includes('accentColor')).to.be.true
expect(keys.includes('premiumType')).to.be.true
expect(keys.includes('publicFlags')).to.be.true
})
})
})
// TODO fix this test, needs proper error handling in rest
// it('With an invalid user id', async () => {
// const user = await rest.getUser('123')
// console.log('user fail', user)
// expect(await rest.getUser('123')).to.throw
// })
})
})
+12
View File
@@ -0,0 +1,12 @@
import type { Camelize, DiscordGuild } from '@discordeno/types'
import { createRestManager } from '../src/manager.js'
import { token } from './constants.js'
// eslint-disable-next-line prefer-const
export let cached = {
guild: undefined as Camelize<DiscordGuild> | undefined
}
export const rest = createRestManager({
token
})
+7
View File
@@ -0,0 +1,7 @@
{
"all": true,
"src": "src",
"reporter": ["text", "lcov"],
"include": ["src/**/*.ts"],
"exclude": ["tests"]
}
+10
View File
@@ -0,0 +1,10 @@
{
"require": "ts-node/register",
"loader": "ts-node/esm",
"recursive": true,
"timeout": 2000,
"watch-extensions": "ts",
"watch-files": ["src", "tests"],
"enable-source-maps": true,
"parallel": false
}
+31
View File
@@ -0,0 +1,31 @@
{
"minify": true,
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2022",
"keepClassNames": true,
"loose": true,
"minify": {
"compress": {
"unused": true
},
"mangle": true
}
},
"module": {
"type": "es6",
"strict": false,
"strictMode": true,
"lazy": false,
"noInterop": false
},
"sourceMaps": "inline"
}
+145
View File
@@ -0,0 +1,145 @@
import Benchmark from 'benchmark'
import TRANSFORMERS from '../src/index.js'
const suite = new Benchmark.Suite()
// Fetch the cached guild
const discordGuild = JSON.parse(
await (
await fetch(
'https://raw.githubusercontent.com/discordeno/discordeno/benchies/cache/cachedObject/guild.json'
)
).text()
)
const guild = TRANSFORMERS.guild(discordGuild)
suite.add('[Transformer] snake Guild to a camel Guild', () => {
TRANSFORMERS.guild(discordGuild)
})
suite.add('[Transformer] camel Guild to a snake Guild ', () => {
TRANSFORMERS.reverse.guild(guild)
})
// Fetch the cached user
const discordUser = JSON.parse(
await (
await fetch(
'https://raw.githubusercontent.com/discordeno/discordeno/benchies/cache/cachedObject/user.json'
)
).text()
)
const user = TRANSFORMERS.user(discordUser)
suite.add('[Transformer] snake User to a camel User', () => {
TRANSFORMERS.user(discordUser)
})
suite.add('[Transformer] camel User to a snake User', () => {
TRANSFORMERS.reverse.user(user)
})
for (const channelType of [
'rules',
'announcement-channel',
'moderator-channel',
'text-channel',
'stage-channel',
'voice-channel'
]) {
const discordChannel = JSON.parse(
await (
await fetch(
`https://raw.githubusercontent.com/discordeno/discordeno/benchies/cache/cachedObject/${channelType}.json`
)
).text()
)
let formattedChannelType = channelType
.split('-')
.map((word) => word[0].toUpperCase() + word.slice(1))
.join(' ')
if (formattedChannelType === 'Rules') formattedChannelType = 'Rules Channel'
suite.add(
`[Transformer] snake ${formattedChannelType} to a camel ${formattedChannelType}`,
() => {
TRANSFORMERS.channel(discordChannel)
}
)
const channel = TRANSFORMERS.channel(discordChannel)
suite.add(
`[Transformer] camel ${formattedChannelType} to a snake ${formattedChannelType}`,
() => {
TRANSFORMERS.reverse.channel(channel)
}
)
}
// Fetch the cached member
const discordMember = JSON.parse(
await (
await fetch(
'https://raw.githubusercontent.com/discordeno/discordeno/benchies/cache/cachedObject/member.json'
)
).text()
)
const member = TRANSFORMERS.member(discordMember)
suite.add('[Transformer] snake Member to a camel Member', () => {
TRANSFORMERS.member(discordMember)
})
suite.add('[Transformer] camel Member to a snake Member', () => {
TRANSFORMERS.reverse.member(member)
})
// Fetch the cached role
const discordRole = JSON.parse(
await (
await fetch(
'https://raw.githubusercontent.com/discordeno/discordeno/benchies/cache/cachedObject/role.json'
)
).text()
)
const role = TRANSFORMERS.role(discordRole)
suite.add('[Transformer] snake Role to a camel Role', () => {
TRANSFORMERS.role(discordRole)
})
suite.add('[Transformer] camel Role to a snake Role', () => {
TRANSFORMERS.reverse.role(role)
})
/*
// Fetch the cached message
const discordMessage = JSON.parse(
await (await fetch(
'https://raw.githubusercontent.com/discordeno/discordeno/benchies/cache/cachedObject/message.json'
))
.text()
)
const message = TRANSFORMERS.message(discordMessage)
suite.add('[Transformer] snake Message to a camel Message', () => {
TRANSFORMERS.message(discordMessage)
})
suite.add('[Transformer] camel User to a snake User', () => {
TRANSFORMERS.reverse.message(message)
})
*/
suite
.on('cycle', function (event: any) {
console.log(String(event.target))
})
.run()
+46
View File
@@ -0,0 +1,46 @@
{
"name": "@discordeno/transformer",
"version": "18.0.0-alpha.1",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"type": "module",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/discordeno/discordeno.git"
},
"scripts": {
"build": "swc --delete-dir-on-start src --out-dir dist",
"build:type": "tsc --declaration --emitDeclarationOnly --declarationDir dist",
"release-build": "yarn build && yarn build:type",
"fmt": "eslint --fix \"src/**/*.ts*\"",
"lint": "eslint \"src/**/*.ts*\"",
"test:unit-coverage": "c8 mocha --no-warnings 'tests/**/*.spec.ts'",
"test:unit": "c8 --r lcov mocha --no-warnings 'tests/**/*.spec.ts' && node ../../scripts/coveragePathFixing.js transformer",
"test:deno-unit": "swc tests --delete-dir-on-start --out-dir denoTestsDist && node ../../scripts/fixDenoTestExtension.js && deno test -A --import-map ../../denoImportMap.json denoTestsDist",
"test:unit:watch": "mocha --no-warnings --watch --parallel 'tests/**/*.spec.ts'",
"test:type": "tsc --noEmit",
"test:test-type": "tsc --project tsconfig.test.json",
"bench:build": "swc bench --delete-dir-on-start --out-dir benchDist && node ../../scripts/fixBenchExtension.js"
},
"devDependencies": {
"@discordeno/types": "18.0.0-alpha.1",
"@swc/cli": "^0.1.57",
"@swc/core": "^1.3.21",
"@types/benchmark": "^2.1.2",
"@types/chai": "^4",
"@types/mocha": "^10",
"@types/node": "^18.11.9",
"@types/sinon": "^10.0.13",
"benchmark": "^2.1.4",
"c8": "^7.12.0",
"chai": "^4.3.7",
"eslint": "^8.0.1",
"eslint-config-discordeno": "*",
"microtime": "^3.1.1",
"mocha": "^10.1.0",
"sinon": "^15.0.0",
"tsconfig": "*",
"typescript": "^4.9.3"
}
}
+1
View File
@@ -0,0 +1 @@
export * from './user.js'
+43
View File
@@ -0,0 +1,43 @@
import type { Camelize, DiscordUser } from '@discordeno/types'
export function c1amelize1User (payload: DiscordUser): Camelize<DiscordUser> {
return {
id: payload.id,
bot: payload.bot,
email: payload.email,
flags: payload.flags,
avatar: payload.avatar,
system: payload.system,
banner: payload.banner,
locale: payload.locale,
username: payload.username,
verified: payload.verified,
discriminator: payload.discriminator,
mfaEnabled: payload.mfa_enabled,
accentColor: payload.accent_color,
premiumType: payload.premium_type,
publicFlags: payload.public_flags
}
}
export function s1nakelize1User (payload: Camelize<DiscordUser>): DiscordUser {
return {
id: payload.id,
bot: payload.bot,
email: payload.email,
flags: payload.flags,
avatar: payload.avatar,
system: payload.system,
banner: payload.banner,
locale: payload.locale,
username: payload.username,
verified: payload.verified,
discriminator: payload.discriminator,
mfa_enabled: payload.mfaEnabled,
accent_color: payload.accentColor,
premium_type: payload.premiumType,
public_flags: payload.publicFlags
}
}
+13
View File
@@ -0,0 +1,13 @@
import { c1amelize1User, s1nakelize1User } from './casing/user.js'
export * from './casing/index.js'
export const TRANSFORMERS = {
user: c1amelize1User,
reverse: {
user: s1nakelize1User
}
}
export default TRANSFORMERS
+1
View File
@@ -0,0 +1 @@
export {}
+16
View File
@@ -0,0 +1,16 @@
{
"extends": "tsconfig/base.json",
"compilerOptions": {
"outDir": "./dist",
},
"include": [
"./src/**/*.ts",
"./src/**/*.tsx"
],
"exclude": [
"node_modules",
"dist",
"test",
"tests"
]
}
+11
View File
@@ -0,0 +1,11 @@
{
"extends": "tsconfig/test.json",
"include": [
"tests",
],
"exclude": [
"node_modules",
"dist",
"src"
]
}
+2 -1
View File
@@ -18,7 +18,8 @@
"skipLibCheck": true,
"strict": true,
"incremental": true,
"importsNotUsedAsValues": "error"
"importsNotUsedAsValues": "error",
"resolveJsonModule": true
},
"exclude": [
"node_modules",
+88
View File
@@ -25,6 +25,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@discordeno/rest@workspace:packages/rest"
dependencies:
"@discordeno/transformer": 18.0.0-alpha.1
"@discordeno/types": 18.0.0-alpha.1
"@swc/cli": ^0.1.57
"@swc/core": ^1.3.21
@@ -47,6 +48,31 @@ __metadata:
languageName: unknown
linkType: soft
"@discordeno/transformer@18.0.0-alpha.1, @discordeno/transformer@workspace:packages/transformer":
version: 0.0.0-use.local
resolution: "@discordeno/transformer@workspace:packages/transformer"
dependencies:
"@discordeno/types": 18.0.0-alpha.1
"@swc/cli": ^0.1.57
"@swc/core": ^1.3.21
"@types/benchmark": ^2.1.2
"@types/chai": ^4
"@types/mocha": ^10
"@types/node": ^18.11.9
"@types/sinon": ^10.0.13
benchmark: ^2.1.4
c8: ^7.12.0
chai: ^4.3.7
eslint: ^8.0.1
eslint-config-discordeno: "*"
microtime: ^3.1.1
mocha: ^10.1.0
sinon: ^15.0.0
tsconfig: "*"
typescript: ^4.9.3
languageName: unknown
linkType: soft
"@discordeno/types@18.0.0-alpha.1, @discordeno/types@workspace:packages/types":
version: 0.0.0-use.local
resolution: "@discordeno/types@workspace:packages/types"
@@ -411,6 +437,13 @@ __metadata:
languageName: node
linkType: hard
"@types/benchmark@npm:^2.1.2":
version: 2.1.2
resolution: "@types/benchmark@npm:2.1.2"
checksum: dc5e544ffca59bdc61008d89f007c14c281c17e80d50385da81eb9182e4466a9208ceb7af72ddfb4df1e2445ea35f2af36854168f698edd4c015a4262232462d
languageName: node
linkType: hard
"@types/chai-as-promised@npm:^7":
version: 7.1.5
resolution: "@types/chai-as-promised@npm:7.1.5"
@@ -860,6 +893,16 @@ __metadata:
languageName: node
linkType: hard
"benchmark@npm:^2.1.4":
version: 2.1.4
resolution: "benchmark@npm:2.1.4"
dependencies:
lodash: ^4.17.4
platform: ^1.3.3
checksum: aa466561d4f2b0a2419a3069b8f90fd35ffacf26849697eea9de525ecfbd10b44da11070cc51c88d772076db8cb2415641b493de7d6c024fdf8551019c6fcf1c
languageName: node
linkType: hard
"bin-check@npm:^4.1.0":
version: 4.1.0
resolution: "bin-check@npm:4.1.0"
@@ -3313,6 +3356,13 @@ __metadata:
languageName: node
linkType: hard
"lodash@npm:^4.17.4":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
languageName: node
linkType: hard
"log-symbols@npm:4.1.0":
version: 4.1.0
resolution: "log-symbols@npm:4.1.0"
@@ -3473,6 +3523,17 @@ __metadata:
languageName: node
linkType: hard
"microtime@npm:^3.1.1":
version: 3.1.1
resolution: "microtime@npm:3.1.1"
dependencies:
node-addon-api: ^5.0.0
node-gyp: latest
node-gyp-build: ^4.4.0
checksum: 1161571d9c994070139d8dd65160bb5ebb87044cb0ea9828a65fde201fcf9b90da9c2897e352a26e852a7fa9dd7b6774128b50854462d117be1b019abff41887
languageName: node
linkType: hard
"mime-db@npm:^1.28.0":
version: 1.52.0
resolution: "mime-db@npm:1.52.0"
@@ -3733,6 +3794,26 @@ __metadata:
languageName: node
linkType: hard
"node-addon-api@npm:^5.0.0":
version: 5.0.0
resolution: "node-addon-api@npm:5.0.0"
dependencies:
node-gyp: latest
checksum: 7c5e2043ac37f6108784d94ed73a44ae6d3e68eb968de60680922fc6bc3d17fa69448c0feb4e0c9d3f4c74a0324822e566a8340a56916d9d6f23cb3e85620334
languageName: node
linkType: hard
"node-gyp-build@npm:^4.4.0":
version: 4.5.0
resolution: "node-gyp-build@npm:4.5.0"
bin:
node-gyp-build: bin.js
node-gyp-build-optional: optional.js
node-gyp-build-test: build-test.js
checksum: d888bae0fb88335f69af1b57a2294a931c5042f36e413d8d364c992c9ebfa0b96ffe773179a5a2c8f04b73856e8634e09cce108dbb9804396d3cc8c5455ff2db
languageName: node
linkType: hard
"node-gyp@npm:latest":
version: 9.3.1
resolution: "node-gyp@npm:9.3.1"
@@ -4116,6 +4197,13 @@ __metadata:
languageName: node
linkType: hard
"platform@npm:^1.3.3":
version: 1.3.6
resolution: "platform@npm:1.3.6"
checksum: 6f472a09c61d418c7e26c1c16d0bdc029549d512dbec6526216a1e59ec68100d07007d0097dcba69dddad883d6f2a83361b4bdfe0094a3d9a2af24158643d85e
languageName: node
linkType: hard
"prelude-ls@npm:^1.2.1":
version: 1.2.1
resolution: "prelude-ls@npm:1.2.1"