@saykit/carbon 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/dist/index.d.mts +65 -0
- package/dist/index.mjs +127 -0
- package/package.json +48 -3
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @saykit/carbon
|
|
2
|
+
|
|
3
|
+
> [Carbon](https://carbon.buape.com) Discord bot integration for [SayKit](https://saykit.js.org).
|
|
4
|
+
|
|
5
|
+
Registers a shared `Say` with your Carbon client, helps command and component classes expose translated metadata, and adds locale-aware `interaction.say` and `guild.say` properties.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @saykit/carbon saykit @buape/carbon
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { Client, Command, type CommandInteraction } from '@buape/carbon';
|
|
17
|
+
import { SayPlugin, withSay } from '@saykit/carbon';
|
|
18
|
+
import { type Say } from 'saykit';
|
|
19
|
+
import say from './i18n.js';
|
|
20
|
+
|
|
21
|
+
class PingCommand extends withSay(Command) {
|
|
22
|
+
constructor(say: Say) {
|
|
23
|
+
super(say, (say) => ({
|
|
24
|
+
name: say`ping`,
|
|
25
|
+
description: say`Ping the bot!`,
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async run(interaction: CommandInteraction) {
|
|
30
|
+
await interaction.reply({ content: interaction.say`Pong!` });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const client = new Client(
|
|
35
|
+
{
|
|
36
|
+
/* options */
|
|
37
|
+
},
|
|
38
|
+
{ commands: [new PingCommand(say)] },
|
|
39
|
+
[new SayPlugin(say)],
|
|
40
|
+
);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Documentation
|
|
44
|
+
|
|
45
|
+
[Carbon integration guide](https://saykit.js.org/integrations/carbon) at [saykit.js.org](https://saykit.js.org).
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { APIInteraction, BaseCommand, BaseComponent, Modal, Plugin } from "@buape/carbon";
|
|
2
|
+
import { Say } from "saykit";
|
|
3
|
+
|
|
4
|
+
//#region src/constants.d.ts
|
|
5
|
+
declare const kSay: unique symbol;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/extensions/base-interaction.d.ts
|
|
8
|
+
declare module '@buape/carbon' {
|
|
9
|
+
interface BaseInteraction<T extends APIInteraction> {
|
|
10
|
+
get say(): Say;
|
|
11
|
+
[kSay]: Say;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
declare function applyBaseInteractionExtension(): () => void;
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/extensions/guild.d.ts
|
|
17
|
+
declare module '@buape/carbon' {
|
|
18
|
+
interface Guild {
|
|
19
|
+
get say(): Say;
|
|
20
|
+
[kSay]: Say;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
declare function applyGuildExtension(): () => void;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/mixers/with-say.d.ts
|
|
26
|
+
type Keys = 'name' | 'description' | 'label' | 'title' | 'placeholder' | 'content' | 'options' | 'components' | 'subcommands' | 'subcommandGroups';
|
|
27
|
+
type AbstractConstructor<Args extends any[] = any[], Instance extends object = object> = abstract new (...args: Args) => Instance;
|
|
28
|
+
type SayProps<T> = Pick<T, Extract<keyof T, Keys>>;
|
|
29
|
+
/**
|
|
30
|
+
* Enhances a {@link BaseCommand} subclass with support for localisation.
|
|
31
|
+
*
|
|
32
|
+
* @param Base Abstract command constructor to extend.
|
|
33
|
+
* @returns A new constructor that accepts a {@link Say} instance, a
|
|
34
|
+
* properties-mapping function, and the original constructor arguments.
|
|
35
|
+
*/
|
|
36
|
+
declare function withSay<Args extends unknown[], Instance extends BaseCommand>(Base: AbstractConstructor<Args, Instance>): AbstractConstructor<[say: Say, properties: (say: Say) => SayProps<Instance>, ...args: Args], Instance & Partial<Record<Keys, unknown>>>;
|
|
37
|
+
/**
|
|
38
|
+
* Enhances a {@link BaseComponent} or {@link Modal} subclass with
|
|
39
|
+
* support for localisation.
|
|
40
|
+
*
|
|
41
|
+
* @param Base Abstract component or modal constructor to extend.
|
|
42
|
+
* @returns A new constructor that accepts a set of properties.
|
|
43
|
+
*/
|
|
44
|
+
declare function withSay<Args extends unknown[], Instance extends BaseComponent | Modal>(Base: AbstractConstructor<Args, Instance>): AbstractConstructor<[properties: SayProps<Instance>, ...args: Args], Instance & Partial<Record<Keys, unknown>>>;
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/plugin.d.ts
|
|
47
|
+
/**
|
|
48
|
+
* A Carbon plugin that provides a singleton {@link Say} instance.
|
|
49
|
+
*
|
|
50
|
+
* `SayPlugin` registers a {@link Say} instance globally and
|
|
51
|
+
* applies interaction and guild-level extensions so that commands and
|
|
52
|
+
* other handlers can access localisation utilities directly.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* const say = new Say({ ... });
|
|
57
|
+
* const client = new Client({ ... }, { ... }, [new SayPlugin(say)]);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare class SayPlugin extends Plugin {
|
|
61
|
+
id: string;
|
|
62
|
+
constructor(say: Say);
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { SayPlugin, applyBaseInteractionExtension, applyGuildExtension, withSay };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { BaseCommand, BaseComponent, BaseInteraction, Guild, Locale, Modal, Plugin } from "@buape/carbon";
|
|
2
|
+
//#region src/utils/combine-command-options.ts
|
|
3
|
+
const ALLOWED_LOCALES = Object.values(Locale);
|
|
4
|
+
function combineCommandOptions(mappedOptions, baseLocale) {
|
|
5
|
+
const options = mappedOptions[baseLocale];
|
|
6
|
+
const availableLocales = Object.keys(mappedOptions).filter((l) => l !== baseLocale && ALLOWED_LOCALES.includes(l));
|
|
7
|
+
for (const [key, value] of Object.entries(options)) if (key === "name" || key === "description") {
|
|
8
|
+
options[`${key}Localizations`] = {};
|
|
9
|
+
for (const locale of availableLocales) {
|
|
10
|
+
const other = mappedOptions[locale][key];
|
|
11
|
+
options[`${key}Localizations`][locale] = other;
|
|
12
|
+
}
|
|
13
|
+
options[`${key}_localizations`] = options[`${key}Localizations`];
|
|
14
|
+
} else if ((key === "options" || key === "choices") && Array.isArray(value)) for (const [index, option] of Object.entries(value)) {
|
|
15
|
+
const mapped = { [baseLocale]: option };
|
|
16
|
+
for (const locale of availableLocales) mapped[locale] = mappedOptions[locale][key][index];
|
|
17
|
+
const combined = combineCommandOptions(mapped, baseLocale);
|
|
18
|
+
options[key][index] = combined;
|
|
19
|
+
}
|
|
20
|
+
return options;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/mixers/with-say.ts
|
|
24
|
+
const ClassMap = /* @__PURE__ */ new WeakMap();
|
|
25
|
+
/**
|
|
26
|
+
* Factory function that creates a "withSay" wrapper around a base class.
|
|
27
|
+
*
|
|
28
|
+
* @param Base The base class constructor.
|
|
29
|
+
* @returns A subclass of the given base class with extra for localisation.
|
|
30
|
+
* @throws If the base class is neither a {@link BaseCommand} nor a
|
|
31
|
+
* {@link BaseComponent}.
|
|
32
|
+
*/
|
|
33
|
+
function withSay(Base) {
|
|
34
|
+
if (ClassMap.has(Base)) return ClassMap.get(Base);
|
|
35
|
+
if (Base.prototype instanceof BaseCommand) {
|
|
36
|
+
const Derived = createSayCommand(Base);
|
|
37
|
+
ClassMap.set(Base, Derived);
|
|
38
|
+
return Derived;
|
|
39
|
+
}
|
|
40
|
+
if (Base.prototype instanceof BaseComponent || Base === Modal) {
|
|
41
|
+
const Derived = createSayComponent(Base);
|
|
42
|
+
ClassMap.set(Base, Derived);
|
|
43
|
+
return Derived;
|
|
44
|
+
}
|
|
45
|
+
throw new Error("Invalid base class");
|
|
46
|
+
}
|
|
47
|
+
function createSayCommand(Base) {
|
|
48
|
+
class SayCommand extends Base {
|
|
49
|
+
constructor(say, properties, ...args) {
|
|
50
|
+
super(...args);
|
|
51
|
+
const options = combineCommandOptions(Array.from(say).reduce((acc, [s, l]) => {
|
|
52
|
+
acc[l] = properties(s);
|
|
53
|
+
return acc;
|
|
54
|
+
}, {}), say.locale);
|
|
55
|
+
Object.assign(this, options);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return SayCommand;
|
|
59
|
+
}
|
|
60
|
+
function createSayComponent(Base) {
|
|
61
|
+
class SayComponent extends Base {
|
|
62
|
+
constructor(properties, ...args) {
|
|
63
|
+
super(...args);
|
|
64
|
+
if (properties) Object.assign(this, properties);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return SayComponent;
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/constants.ts
|
|
71
|
+
const kSay = Symbol.for("saykit.say");
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/extensions/base-interaction.ts
|
|
74
|
+
function applyBaseInteractionExtension() {
|
|
75
|
+
Object.defineProperty(BaseInteraction.prototype, "say", { get() {
|
|
76
|
+
const say = Reflect.get(globalThis, kSay);
|
|
77
|
+
if (!say) throw new Error("No `say` instance available");
|
|
78
|
+
this[kSay] ??= say.clone();
|
|
79
|
+
const locale = this[kSay].match([this.rawData.locale]);
|
|
80
|
+
this[kSay].activate(locale);
|
|
81
|
+
return this[kSay];
|
|
82
|
+
} });
|
|
83
|
+
return () => {
|
|
84
|
+
Object.defineProperty(BaseInteraction.prototype, "say", { value: void 0 });
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/extensions/guild.ts
|
|
89
|
+
function applyGuildExtension() {
|
|
90
|
+
Object.defineProperty(Guild.prototype, "say", { get() {
|
|
91
|
+
const say = Reflect.get(globalThis, kSay);
|
|
92
|
+
if (!say) throw new Error("No `say` instance available");
|
|
93
|
+
this[kSay] ??= say.clone();
|
|
94
|
+
const locale = this[kSay].match([this.rawData.preferred_locale]);
|
|
95
|
+
this[kSay].activate(locale);
|
|
96
|
+
return this[kSay];
|
|
97
|
+
} });
|
|
98
|
+
return () => {
|
|
99
|
+
Object.defineProperty(Guild.prototype, "say", { value: void 0 });
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/plugin.ts
|
|
104
|
+
/**
|
|
105
|
+
* A Carbon plugin that provides a singleton {@link Say} instance.
|
|
106
|
+
*
|
|
107
|
+
* `SayPlugin` registers a {@link Say} instance globally and
|
|
108
|
+
* applies interaction and guild-level extensions so that commands and
|
|
109
|
+
* other handlers can access localisation utilities directly.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const say = new Say({ ... });
|
|
114
|
+
* const client = new Client({ ... }, { ... }, [new SayPlugin(say)]);
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
var SayPlugin = class extends Plugin {
|
|
118
|
+
id = "saykit";
|
|
119
|
+
constructor(say) {
|
|
120
|
+
super();
|
|
121
|
+
Reflect.set(globalThis, kSay, say);
|
|
122
|
+
applyBaseInteractionExtension();
|
|
123
|
+
applyGuildExtension();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
//#endregion
|
|
127
|
+
export { SayPlugin, withSay };
|
package/package.json
CHANGED
|
@@ -1,4 +1,49 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@saykit/carbon",
|
|
3
|
-
"version": "0.
|
|
1
|
+
{
|
|
2
|
+
"name": "@saykit/carbon",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Carbon Discord framework integration for saykit",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bot",
|
|
7
|
+
"carbon",
|
|
8
|
+
"discord",
|
|
9
|
+
"i18n",
|
|
10
|
+
"saykit"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/k0d13/saykit#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/k0d13/saykit/issues"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/k0d13/saykit.git",
|
|
20
|
+
"directory": "packages/integration-carbon"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"!dist/**/*.map"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
30
|
+
"default": "./dist/index.mjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public",
|
|
35
|
+
"provenance": true
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@buape/carbon": "0.16.0",
|
|
39
|
+
"saykit": "^0.2.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@buape/carbon": "*",
|
|
43
|
+
"saykit": "*"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"check": "tsc --noEmit",
|
|
47
|
+
"build": "tsdown"
|
|
48
|
+
}
|
|
4
49
|
}
|