diff --git a/.gitignore b/.gitignore index 03be642..ab7a14d 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,6 @@ dist .yarn/install-state.gz .pnp.* -config.json \ No newline at end of file +config.json + +*.db \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index c6a5340..1b545c1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,13 +1,13 @@ -{ - "editor.formatOnSave": true, - "typescript.preferences.quoteStyle": "single", - "javascript.preferences.quoteStyle": "single", - "editor.defaultFormatter": "dbaeumer.vscode-eslint", - "eslint.format.enable": true, - "[typescript]": { - "editor.defaultFormatter": "dbaeumer.vscode-eslint" - }, - "[javascript]": { - "editor.defaultFormatter": "dbaeumer.vscode-eslint" - } -} +{ + "editor.formatOnSave": true, + "typescript.preferences.quoteStyle": "single", + "javascript.preferences.quoteStyle": "single", + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "eslint.format.enable": true, + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + } +} diff --git a/goobers b/goobers deleted file mode 100644 index ee3c0eb..0000000 Binary files a/goobers and /dev/null differ diff --git a/src/commands/checkroles.ts b/src/commands/checkroles.ts new file mode 100644 index 0000000..8ed5b39 --- /dev/null +++ b/src/commands/checkroles.ts @@ -0,0 +1,52 @@ +import { + type CommandInteraction, + SlashCommandBuilder, EmbedBuilder, PermissionsBitField +} from 'discord.js' +import { execute, obj2role } from '../db' + +module.exports = { + data: new SlashCommandBuilder() + .setName('checkroles') + .setDescription('Prints all role permissions'), + async execute (interaction: CommandInteraction) { + const role = interaction.options.get('role')?.value + if (role === undefined) { + await interaction.reply({ content: 'Cannot find role', ephemeral: true }) + return + } + if ((interaction.memberPermissions?.has(PermissionsBitField.Flags.ManageRoles, true)) !== true) { + await interaction.reply({ content: 'I am sorry dave, I cannot do that\nYou don\'t have the permission to manage roles on this server', ephemeral: true }) + return + } + // Set Role + + await execute('DELETE FROM permissions WHERE guild=$guild AND role=$role', + { + $guild: interaction.guildId, + $role: role + }) + + const permissions = { + create: Boolean(interaction.options.get('create_permission')?.value), + delete: Boolean(interaction.options.get('delete_permission')?.value) + } + + await execute('INSERT INTO permissions (guild, role, permissions) VALUES($guild, $role, $permissions)', + { + $guild: interaction.guildId, + $role: role, + $permissions: obj2role(permissions) + }) + + const statusUpdate = new EmbedBuilder() + .setColor(0x0099FF) + .setTitle('Role updated successfully') + .addFields( + { name: 'Role', value: `<@&${role.toString()}>` }, + { name: 'Can add goobs', value: permissions.create ? '🟩' : '🟥', inline: true }, + { name: 'Can delete goobs', value: permissions.delete ? '🟩' : '🟥', inline: true } + ) + .setTimestamp() + await interaction.reply({ embeds: [statusUpdate], ephemeral: true }) + } +} diff --git a/src/commands/goob.ts b/src/commands/goob.ts new file mode 100644 index 0000000..64f2a88 --- /dev/null +++ b/src/commands/goob.ts @@ -0,0 +1,73 @@ +import { + type CommandInteraction, + SlashCommandBuilder, EmbedBuilder, type Message, ButtonStyle, ButtonBuilder, ActionRowBuilder, ComponentType +} from 'discord.js' +import { execute } from '../db' + +module.exports = { + data: new SlashCommandBuilder() + .setName('goob') + .setDescription('meow').addIntegerOption(option => + option + .setName('gooberid') + .setDescription('The goob to see') + .setRequired(false)), + async execute (interaction: CommandInteraction) { + // Pick the right goober + const amountOfGoobs = (await execute('SELECT COUNT(*) as totalweight from goob'))[0].totalweight + let number = Number(interaction.options.get('gooberid')?.value) + let targetImage + if (!Number.isNaN(number)) { + targetImage = (await execute('SELECT * from goob WHERE id = $messageid', { $messageid: number }))[0] + } else { + number = Math.ceil(Math.random() * amountOfGoobs) + targetImage = (await execute('WITH indexed as (SELECT *, COUNT(*) over(order by messageid) as theRow from goob) SELECT * from indexed WHERE theRow = $messageid', { $messageid: number }))[0] + } + + // Fetch the original message + const messageGuild = await interaction.client.guilds.fetch(targetImage.guild) + const messageChannel = await messageGuild.channels.fetch(targetImage.channel) + let message = undefined as Message | undefined + + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if (messageChannel?.isTextBased()) { + message = await messageChannel.messages.fetch(targetImage.messageid).catch(() => undefined) + } + + // Check if goob is a video or not and send the goob + const data = await fetch(targetImage.url) + const contentType = data.headers.get('content-type') + + let exampleEmbed = new EmbedBuilder() + .setColor(0x0099FF) + .setTitle(`Goob #${targetImage.id as number}`) + .setURL(message?.url ?? targetImage.url) + .setTimestamp(message?.createdTimestamp ?? undefined) + .setAuthor({ name: message?.author.username ?? 'deleted message', iconURL: message?.author.avatarURL() ?? undefined, url: message?.url }) + + let files: any[] | undefined + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if (contentType?.startsWith('video')) { + files = [{ attachment: targetImage.url }] + } else { + exampleEmbed = exampleEmbed.setImage(targetImage.url) + } + + const gulag = new ButtonBuilder() + .setCustomId('Delete') + .setLabel('Delete') + .setStyle(ButtonStyle.Danger) + + const row = new ActionRowBuilder() + .addComponents(gulag) as any + const response = await interaction.reply({ embeds: [exampleEmbed], files, components: [row] }) + + const collector = response.createMessageComponentCollector({ componentType: ComponentType.Button, time: 3_600_00 }) + + collector.on('collect', async i => { + const roles = (await execute('SELECT * from permissions WHERE guild = $guild', { $guild: i.guild?.id })) + console.log(roles) + console.log(i.member?.roles) + }) + } +} diff --git a/src/commands/load.ts b/src/commands/load.ts index f3e3561..5cc040f 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -1,54 +1,138 @@ -import { type CommandInteraction, SlashCommandBuilder, type Message } from 'discord.js' +import { + type CommandInteraction, + SlashCommandBuilder, + type Message +} from 'discord.js' import { owner_id } from '../config.json' import db from '../db' +function insertGoob (message: Message): void { + const attachments = message.attachments.filter( + (e) => + e.contentType !== null && + (e.contentType?.startsWith('image') || e.contentType?.startsWith('video')) + ) + + const embeds = message.embeds.filter((e) => e.image !== undefined || e.video !== undefined) + + attachments.forEach(a => db.run('INSERT INTO goob (messageid, guild, channel, url) VALUES ($messageid, $guild, $channel, $url)', { + $messageid: message.id, + $guild: message.guildId, + $channel: message.channelId, + $url: a.url + })) + + embeds.forEach(e => db.run('INSERT INTO goob (messageid, guild, channel, url) VALUES ($messageid, $guild, $channel, $url)', { + $messageid: message.id, + $guild: message.guildId, + $channel: message.channelId, + $url: e.video !== undefined ? e.video?.url : e.image?.url + })) + + if (attachments.size > 0 || embeds.length > 0) void message.react('📥') +} + module.exports = { data: new SlashCommandBuilder() .setName('load') - .setDescription('Provides information about the user.'), + .setDescription('Sync data for '), async execute (interaction: CommandInteraction) { if (interaction.user.id !== owner_id) { - await interaction.reply({ content: 'You do not have access to this command!', ephemeral: true }) + await interaction.reply({ + content: 'You do not have access to this command!', + ephemeral: true + }) } - if (interaction.channel?.isDMBased() === true) { - await interaction.reply({ content: 'This command is disabled for DM channels', ephemeral: true }) + if ( + interaction.channel?.isDMBased() === true || + interaction.guild === undefined + ) { + await interaction.reply({ + content: 'This command is disabled for DM channels', + ephemeral: true + }) return } + + db.run('DELETE FROM goob WHERE guild = $guild', { + $guild: interaction.guildId + }) + db.run('DELETE FROM tracked WHERE guild = $guild', { + $guild: interaction.guildId + }) + let loaded = 0 - const images = new Set() - let messages = await interaction.channel?.messages.fetch().catch(console.error) + const loadedImages = 0 + let messages = await interaction.channel?.messages + .fetch() + .catch(console.error) if (messages === undefined) { - await interaction.reply('Couldn\'t fetch messages') + await interaction.reply("Couldn't fetch messages") return } loaded += messages.size - await interaction.reply(`Loading messages... loaded ${loaded} with ${images.size} images`) + await interaction.reply( + `Loading messages... loaded ${loaded} with ${loadedImages} images` + ) while (messages !== undefined && messages.size > 0) { - const imagesURL = (messages as unknown as Message[]).map(e => e.attachments).filter(e => e.size > 0).map(e => e.map(v => v)).flat().filter(e => e.contentType?.startsWith('image')).map(e => e.url).flat() - imagesURL.forEach(images.add, images) + (messages as unknown as Message[]) + .map((e) => e).filter(e => !e.author.bot) + .filter( + (e) => + e.attachments.filter( + (e) => + e.contentType !== null && + (e.contentType?.startsWith('image') || + e.contentType?.startsWith('video')) + ).size > 0 + ).map(insertGoob); + + (messages as unknown as Message[]) + .map((e) => e).filter(e => !e.author.bot) + .filter( + (e) => + e.embeds.filter( + (e) => e.image !== undefined + ).length > 0 + ).map(insertGoob) + const lastmessage = messages.last() as Message | undefined if (lastmessage === undefined) { - await interaction.editReply('Coudn\'t fetch message data') + await interaction.editReply("Coudn't fetch message data") break } - await interaction.editReply(`Loading messages... loaded ${loaded} messages with ${images.size} images`) + await interaction.editReply( + `Loading messages... loaded ${loaded} messages with ${loadedImages} images` + ) - messages = await interaction.channel?.messages.fetch({ before: lastmessage.id }).catch(console.error) + messages = await interaction.channel?.messages + .fetch({ before: lastmessage.id }) + .catch(console.error) if (messages !== undefined) loaded += messages.size } - await interaction.editReply(`Loading complete ! loaded ${loaded} messages with ${images.size} images`) - const stmt = db.prepare('INSERT INTO goob VALUES (?)') + await interaction.editReply( + `Loading complete ! loaded ${loaded} messages with ${loadedImages} images` + ) - images.forEach(e => stmt.run(e)) - stmt.finalize() + const reply = await interaction.fetchReply() + if (reply === undefined) { + await interaction.reply({ + content: 'Impossible to fetch reply. Did something go wrong ?', + ephemeral: true + }) + return + } + db.run( + 'INSERT INTO tracked (guild, last_message, channel) VALUES ($guild, $last_message, $channel)', + { + $guild: interaction.guildId, + $channel: interaction.channelId, + $last_message: reply.id + } + ) - db.each('SELECT rowid AS id, url FROM goob', (err, row: any) => { - console.log(`${row.id as string} : ${row.url as string}`) - if (err != null) console.error(err) - }) - console.log(images) // interaction.user is the object representing the User who ran the command // interaction.member is the GuildMember object, which represents the user in the specific guild // await interaction.reply(`This command was run by ${interaction.user.username}`) diff --git a/src/commands/setrole.ts b/src/commands/setrole.ts new file mode 100644 index 0000000..4ac0127 --- /dev/null +++ b/src/commands/setrole.ts @@ -0,0 +1,70 @@ +import { + type CommandInteraction, + SlashCommandBuilder, EmbedBuilder, PermissionsBitField +} from 'discord.js' +import { execute, obj2role } from '../db' + +module.exports = { + data: new SlashCommandBuilder() + .setName('setrole') + .setDescription('Adds permissions to a discord role') + .addRoleOption(option => + option + .setName('role') + .setDescription('The role') + .setRequired(true)) + .addBooleanOption(option => + option + .setName('delete_permission') + .setDescription('Permission to delete goobs') + .setRequired(true)) + .addBooleanOption(option => + option + .setName('create_permission') + .setDescription('Permission to add goobs') + .setRequired(true)), + async execute (interaction: CommandInteraction) { + /* const totalweight = (await execute('SELECT SUM(weight) as totalweight from goob'))[0].totalweight + const number = Math.floor(Math.random() * totalweight) */ + + const role = interaction.options.get('role')?.value + if (role === undefined) { + await interaction.reply({ content: 'Cannot find role', ephemeral: true }) + return + } + if ((interaction.memberPermissions?.has(PermissionsBitField.Flags.ManageRoles, true)) !== true) { + await interaction.reply({ content: 'I am sorry dave, I cannot do that\nYou don\'t have the permission to manage roles on this server', ephemeral: true }) + return + } + // Set Role + + await execute('DELETE FROM permissions WHERE guild=$guild AND role=$role', + { + $guild: interaction.guildId, + $role: role + }) + + const permissions = { + create: Boolean(interaction.options.get('create_permission')?.value), + delete: Boolean(interaction.options.get('delete_permission')?.value) + } + + await execute('INSERT INTO permissions (guild, role, permissions) VALUES($guild, $role, $permissions)', + { + $guild: interaction.guildId, + $role: role, + $permissions: obj2role(permissions) + }) + + const statusUpdate = new EmbedBuilder() + .setColor(0x0099FF) + .setTitle('Role updated successfully') + .addFields( + { name: 'Role', value: `<@&${role.toString()}>` }, + { name: 'Can add goobs', value: permissions.create ? '🟩' : '🟥', inline: true }, + { name: 'Can delete goobs', value: permissions.delete ? '🟩' : '🟥', inline: true } + ) + .setTimestamp() + await interaction.reply({ embeds: [statusUpdate], ephemeral: true }) + } +} diff --git a/src/db/index.ts b/src/db/index.ts index cb373ea..206c3a4 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,9 +1,35 @@ import { verbose } from 'sqlite3' const sqlite = verbose() -const db = new sqlite.Database('goobers') +const db = new sqlite.Database('goobers.db') + +export async function execute (query: string, args = {} as any): Promise { + return await new Promise((resolve, reject) => { + db.all(query, args, (err: string, rows: any) => { + if (err !== null) { + reject(err) + console.error(err) + return + } + resolve(rows) + }) + }) +} db.serialize(() => { - db.run('CREATE TABLE IF NOT EXISTS goob (url TEXT UNIQUE)') + db.run('CREATE TABLE IF NOT EXISTS goob (id INTEGER PRIMARY KEY AUTOINCREMENT, messageid TEXT, guild TEXT, channel TEXT, url TEXT NOT NULL UNIQUE)') + db.run('CREATE TABLE IF NOT EXISTS tracked (guild TEXT UNIQUE, last_message TEXT, channel TEXT)') + db.run('CREATE TABLE IF NOT EXISTS permissions (guild TEXT NOT NULL, role TEXT NOT NULL, permissions INTEGER, PRIMARY KEY (guild, role))') }) +export function role2obj (role: number): { create: boolean, delete: boolean } { + return { + create: Boolean(role & 1), + delete: Boolean(role & 2) + } +} + +export function obj2role (role: ReturnType): number { + return Number(role.create) | (Number(role.delete) * 2) +} + export default db diff --git a/src/syncCommands.ts b/src/syncCommands.ts index 23e43ac..32c7a05 100644 --- a/src/syncCommands.ts +++ b/src/syncCommands.ts @@ -9,13 +9,12 @@ const commands = [] as SlashCommand[] const commandsPath = path.join(__dirname, 'commands') const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')) -console.log(commandFiles) const promises = [] as Array> for (const file of commandFiles) { const filePath = path.join(commandsPath, file) promises.push(import(filePath).then(({ default: command }) => { if ('data' in command && 'execute' in command) { - commands.push(command) + commands.push(command.data.toJSON()) } else { console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`) } @@ -36,6 +35,7 @@ void Promise.all(promises).then(async () => { const data = await rest.put( Routes.applicationGuildCommands(discord_app_id, discord_guild_id), { body: commands } + ) console.log(`Successfully reloaded ${(data as string[]).length} application (/) commands.`) diff --git a/tsconfig.json b/tsconfig.json index 5a9540a..68c5a2f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,108 +1,109 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./" /* Specify the root folder within your source files. */, - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - "baseUrl": "." /* Specify the base directory to resolve non-relative module names. */, - /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - "typeRoots": [ - "node_modules/@types", - "src/@types" - ] /* Specify multiple folders that act like './node_modules/@types'. */, - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - "resolveJsonModule": true /* Enable importing .json files. */, - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - "sourceMap": true /* Create source map files for emitted JavaScript files. */, - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./out/" /* Specify an output folder for all emitted files. */, - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - }, - "compileOnSave": true, - "exclude": ["jest.config.ts", "./tests"] -} +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./" /* Specify the root folder within your source files. */, + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "." /* Specify the base directory to resolve non-relative module names. */, + /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + "typeRoots": [ + "node_modules/@types", + "src/@types" + ] /* Specify multiple folders that act like './node_modules/@types'. */, + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + "resolveJsonModule": true /* Enable importing .json files. */, + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + "sourceMap": true /* Create source map files for emitted JavaScript files. */, + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./out/" /* Specify an output folder for all emitted files. */, + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "compileOnSave": true, + "exclude": ["jest.config.ts", "./tests"], + "include": ["./src"] +}