From fb9148ada5077028a4766ec6b986c23903a8ae10 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 20 Nov 2024 16:21:35 -0500 Subject: [PATCH] Site runs and all tests pass --- client/homebrew/brewRenderer/brewRenderer.jsx | 2 +- .../notificationPopup/notificationPopup.jsx | 2 +- client/homebrew/editor/editor.jsx | 2 +- .../editor/metadataEditor/metadataEditor.jsx | 2 +- .../basePages/listPage/brewItem/brewItem.jsx | 2 +- client/homebrew/pages/editPage/editPage.jsx | 4 +- client/homebrew/pages/errorPage/errorPage.jsx | 2 +- client/homebrew/pages/homePage/homePage.jsx | 2 +- client/homebrew/pages/newPage/newPage.jsx | 4 +- client/homebrew/pages/vaultPage/vaultPage.jsx | 2 +- client/homebrew/utils/request-middleware.js | 4 +- client/template.js | 6 +- package-lock.json | 24 ++++++ package.json | 6 +- scripts/buildHomebrew.js | 29 ++++---- server.js | 8 +- server/admin.api.js | 22 +++--- server/admin.api.spec.js | 9 ++- server/app.js | 73 +++++++++++-------- server/brewDefaults.js | 4 +- server/config.js | 12 +-- server/db.js | 8 +- server/forcessl.mw.js | 2 +- server/googleActions.js | 13 ++-- server/homebrew.api.js | 30 ++++---- server/homebrew.api.spec.js | 7 +- server/homebrew.model.js | 17 +++-- server/middleware/check-client-version.js | 6 +- server/middleware/content-negotiation.js | 4 +- server/middleware/content-negotiation.spec.js | 41 ----------- server/notifications.model.js | 10 +-- server/static-assets.mv.js | 4 +- server/token.js | 10 +-- server/vault.api.js | 8 +- shared/helpers.js | 8 +- shared/naturalcrit/markdown.js | 30 ++++---- tests/markdown/basic.test.js | 2 +- tests/markdown/definition-lists.test.js | 2 +- tests/markdown/emojis.test.js | 2 +- tests/markdown/hard-breaks.test.js | 2 +- tests/markdown/mustache-syntax.test.js | 2 +- tests/markdown/variables.test.js | 2 +- tests/routes/static-pages.test.js | 6 +- themes/V3/Blank/snippets/footer.gen.js | 2 +- themes/fonts/iconFonts/diceFont.js | 2 +- themes/fonts/iconFonts/elderberryInn.js | 2 +- themes/fonts/iconFonts/fontAwesome.js | 2 +- themes/fonts/iconFonts/gameIcons.js | 2 +- 48 files changed, 230 insertions(+), 217 deletions(-) delete mode 100644 server/middleware/content-negotiation.spec.js diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 4685775b9..36d263040 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -5,7 +5,7 @@ const { useState, useRef, useCallback, useMemo } = React; const _ = require('lodash'); const MarkdownLegacy = require('naturalcrit/markdownLegacy.js'); -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; const ErrorBar = require('./errorBar/errorBar.jsx'); const ToolBar = require('./toolBar/toolBar.jsx'); diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx index 3ea165d62..0c8fc4b8c 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx @@ -1,6 +1,6 @@ require('./notificationPopup.less'); import React, { useEffect, useState } from 'react'; -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; import Dialog from '../../../components/dialog.jsx'; diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 9fef72cbb..bba5f3ad9 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -4,7 +4,7 @@ const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); const dedent = require('dedent-tabs').default; -const Markdown = require('../../../shared/naturalcrit/markdown.js'); +import Markdown from '../../../shared/naturalcrit/markdown.js'; const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx'); const SnippetBar = require('./snippetbar/snippetbar.jsx'); diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0e06b2c72..bfc3b8b61 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -3,7 +3,7 @@ require('./metadataEditor.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; const Nav = require('naturalcrit/nav/nav.jsx'); const Combobox = require('client/components/combobox.jsx'); const TagInput = require('../tagInput/tagInput.jsx'); diff --git a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx index 039bc98f5..9011564a3 100644 --- a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx +++ b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx @@ -2,7 +2,7 @@ require('./brewItem.less'); const React = require('react'); const createClass = require('create-react-class'); const moment = require('moment'); -const request = require('../../../../utils/request-middleware.js'); +import request from '../../../../utils/request-middleware.js'; const googleDriveIcon = require('../../../../googleDrive.svg'); const homebreweryIcon = require('../../../../thumbnail.png'); diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 7ddf0bb06..889fd58c5 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -4,7 +4,7 @@ const React = require('react'); const _ = require('lodash'); const createClass = require('create-react-class'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; const { Meta } = require('vitreum/headtags'); const Nav = require('naturalcrit/nav/nav.jsx'); @@ -23,7 +23,7 @@ const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); const LockNotification = require('./lockNotification/lockNotification.jsx'); -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js'); const { printCurrentBrew, fetchThemeBundle } = require('../../../../shared/helpers.js'); diff --git a/client/homebrew/pages/errorPage/errorPage.jsx b/client/homebrew/pages/errorPage/errorPage.jsx index 387a99b02..4ac73da8c 100644 --- a/client/homebrew/pages/errorPage/errorPage.jsx +++ b/client/homebrew/pages/errorPage/errorPage.jsx @@ -1,7 +1,7 @@ require('./errorPage.less'); const React = require('react'); const UIPage = require('../basePages/uiPage/uiPage.jsx'); -const Markdown = require('../../../../shared/naturalcrit/markdown.js'); +import Markdown from '../../../../shared/naturalcrit/markdown.js'; const ErrorIndex = require('./errors/errorIndex.js'); const ErrorPage = ({ brew })=>{ diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index f737506f1..00d0c801d 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -2,7 +2,7 @@ require('./homePage.less'); const React = require('react'); const createClass = require('create-react-class'); const cx = require('classnames'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; const { Meta } = require('vitreum/headtags'); const Nav = require('naturalcrit/nav/nav.jsx'); diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 8216b347c..ee2c67d5f 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -2,9 +2,9 @@ require('./newPage.less'); const React = require('react'); const createClass = require('create-react-class'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; const Nav = require('naturalcrit/nav/nav.jsx'); const PrintNavItem = require('../../navbar/print.navitem.jsx'); diff --git a/client/homebrew/pages/vaultPage/vaultPage.jsx b/client/homebrew/pages/vaultPage/vaultPage.jsx index fbf15f814..21a8e8363 100644 --- a/client/homebrew/pages/vaultPage/vaultPage.jsx +++ b/client/homebrew/pages/vaultPage/vaultPage.jsx @@ -15,7 +15,7 @@ const BrewItem = require('../basePages/listPage/brewItem/brewItem.jsx'); const SplitPane = require('../../../../shared/naturalcrit/splitPane/splitPane.jsx'); const ErrorIndex = require('../errorPage/errors/errorIndex.js'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; const VaultPage = (props)=>{ const [pageState, setPageState] = useState(parseInt(props.query.page) || 1); diff --git a/client/homebrew/utils/request-middleware.js b/client/homebrew/utils/request-middleware.js index f6bc2571b..01a9d2571 100644 --- a/client/homebrew/utils/request-middleware.js +++ b/client/homebrew/utils/request-middleware.js @@ -1,4 +1,4 @@ -const request = require('superagent'); +import request from 'superagent'; const addHeader = (request)=>request.set('Homebrewery-Version', global.version); @@ -9,4 +9,4 @@ const requestMiddleware = { delete : (path)=>addHeader(request.delete(path)), }; -module.exports = requestMiddleware; \ No newline at end of file +export default requestMiddleware; \ No newline at end of file diff --git a/client/template.js b/client/template.js index c77f953ff..990df785c 100644 --- a/client/template.js +++ b/client/template.js @@ -8,6 +8,8 @@ const template = async function(name, title='', props = {}){ }); const ogMetaTags = ogTags.join('\n'); + const ssrModule = await import(`../build/${name}/ssr.cjs`); + return ` @@ -21,7 +23,7 @@ const template = async function(name, title='', props = {}){ ${title.length ? `${title} - The Homebrewery`: 'The Homebrewery - NaturalCrit'} -
${require(`../build/${name}/ssr.js`)(props)}
+
${ssrModule.default(props)}
@@ -29,4 +31,4 @@ const template = async function(name, title='', props = {}){ `; }; -module.exports = template; \ No newline at end of file +export default template; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a9b64c1d7..03f892206 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "license": "MIT", "dependencies": { "@babel/core": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.9", @@ -52,6 +53,7 @@ }, "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", + "babel-plugin-transform-import-meta": "^2.2.1", "eslint": "^9.14.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", @@ -559,6 +561,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -3881,6 +3884,27 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/babel-plugin-transform-import-meta": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.2.1.tgz", + "integrity": "sha512-AxNh27Pcg8Kt112RGa3Vod2QS2YXKKJ6+nSvRtv7qQTJAdx0MZa4UHZ4lnxHUWA2MNbLuZQv5FVab4P1CoLOWw==", + "dev": true, + "license": "BSD", + "dependencies": { + "@babel/template": "^7.4.4", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.0" + } + }, + "node_modules/babel-plugin-transform-import-meta/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", diff --git a/package.json b/package.json index 08473ca05..f5c595a35 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "homebrewery", "description": "Create authentic looking D&D homebrews using only markdown", "version": "3.16.0", + "type": "module", "engines": { "npm": "^10.2.x", "node": "^20.18.x" @@ -83,11 +84,13 @@ "@babel/preset-react" ], "plugins": [ - "@babel/plugin-transform-runtime" + "@babel/plugin-transform-runtime", + "babel-plugin-transform-import-meta" ] }, "dependencies": { "@babel/core": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.9", @@ -129,6 +132,7 @@ }, "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", + "babel-plugin-transform-import-meta": "^2.2.1", "eslint": "^9.14.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", diff --git a/scripts/buildHomebrew.js b/scripts/buildHomebrew.js index f072b0359..313c92db7 100644 --- a/scripts/buildHomebrew.js +++ b/scripts/buildHomebrew.js @@ -1,14 +1,15 @@ -const fs = require('fs-extra'); -const zlib = require('zlib'); -const Proj = require('./project.json'); +import fs from 'fs-extra'; +import zlib from 'zlib'; +import Proj from './project.json' with { type: 'json' }; +import vitreum from 'vitreum'; +const { pack, watchFile, livereload } = vitreum; -const { pack, watchFile, livereload } = require('vitreum'); -const isDev = !!process.argv.find((arg)=>arg=='--dev'); +import lessTransform from 'vitreum/transforms/less.js'; +import assetTransform from 'vitreum/transforms/asset.js'; +import babel from '@babel/core'; +import less from 'less'; -const lessTransform = require('vitreum/transforms/less.js'); -const assetTransform = require('vitreum/transforms/asset.js'); -const babel = require('@babel/core'); -const less = require('less'); +const isDev = !!process.argv.find((arg) => arg === '--dev'); const babelify = async (code)=>(await babel.transformAsync(code, { presets: [['@babel/preset-env', { 'exclude': ['proposal-dynamic-import'] }], '@babel/preset-react'], plugins: ['@babel/plugin-transform-runtime'] })).code; @@ -24,7 +25,7 @@ const build = async ({ bundle, render, ssr })=>{ //css = `@layer bundle {\n${css}\n}`; await fs.outputFile('./build/homebrew/bundle.css', css); await fs.outputFile('./build/homebrew/bundle.js', bundle); - await fs.outputFile('./build/homebrew/ssr.js', ssr); + await fs.outputFile('./build/homebrew/ssr.cjs', ssr); await fs.copy('./client/homebrew/favicon.ico', './build/assets/favicon.ico'); @@ -51,7 +52,7 @@ fs.emptyDirSync('./build'); const themes = { Legacy: {}, V3: {} }; let themeFiles = fs.readdirSync('./themes/Legacy'); - for (dir of themeFiles) { + for (let dir of themeFiles) { const themeData = JSON.parse(fs.readFileSync(`./themes/Legacy/${dir}/settings.json`).toString()); themeData.path = dir; themes.Legacy[dir] = (themeData); @@ -68,7 +69,7 @@ fs.emptyDirSync('./build'); } themeFiles = fs.readdirSync('./themes/V3'); - for (dir of themeFiles) { + for (let dir of themeFiles) { const themeData = JSON.parse(fs.readFileSync(`./themes/V3/${dir}/settings.json`).toString()); themeData.path = dir; themes.V3[dir] = (themeData); @@ -104,14 +105,14 @@ fs.emptyDirSync('./build'); const editorThemesBuildDir = './build/homebrew/cm-themes'; await fs.copy('./node_modules/codemirror/theme', editorThemesBuildDir); await fs.copy('./themes/codeMirror/customThemes', editorThemesBuildDir); - editorThemeFiles = fs.readdirSync(editorThemesBuildDir); + const editorThemeFiles = fs.readdirSync(editorThemesBuildDir); const editorThemeFile = './themes/codeMirror/editorThemes.json'; if(fs.existsSync(editorThemeFile)) fs.rmSync(editorThemeFile); const stream = fs.createWriteStream(editorThemeFile, { flags: 'a' }); stream.write('[\n"default"'); - for (themeFile of editorThemeFiles) { + for (let themeFile of editorThemeFiles) { stream.write(`,\n"${themeFile.slice(0, -4)}"`); } stream.write('\n]\n'); diff --git a/server.js b/server.js index 6cbe07c4f..fe5a9a363 100644 --- a/server.js +++ b/server.js @@ -1,12 +1,12 @@ -const DB = require('./server/db.js'); -const server = require('./server/app.js'); -const config = require('./server/config.js'); +import DB from './server/db.js'; +import server from './server/app.js'; +import config from './server/config.js'; DB.connect(config).then(()=>{ // Ensure that we have successfully connected to the database // before launching server const PORT = process.env.PORT || config.get('web_port') || 8000; - server.app.listen(PORT, ()=>{ + server.listen(PORT, ()=>{ const reset = '\x1b[0m'; // Reset to default style const bright = '\x1b[1m'; // Bright (bold) style const cyan = '\x1b[36m'; // Cyan color diff --git a/server/admin.api.js b/server/admin.api.js index bc179ff7b..02cdcb2f7 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -1,13 +1,15 @@ -const HomebrewModel = require('./homebrew.model.js').model; -const NotificationModel = require('./notifications.model.js').model; -const router = require('express').Router(); -const Moment = require('moment'); -const templateFn = require('../client/template.js'); -const zlib = require('zlib'); +import {model as HomebrewModel } from './homebrew.model.js'; +import {model as NotificationModel } from './notifications.model.js'; +import express from 'express'; +import Moment from 'moment'; +import zlib from 'zlib'; +import templateFn from '../client/template.js'; -const HomebrewAPI = require('./homebrew.api.js'); -const asyncHandler = require('express-async-handler'); -const { splitTextStyleAndMetadata } = require('../shared/helpers.js'); +import HomebrewAPI from './homebrew.api.js'; +import asyncHandler from 'express-async-handler'; +import { splitTextStyleAndMetadata } from '../shared/helpers.js'; + +const router = express.Router(); process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin'; process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3'; @@ -190,4 +192,4 @@ router.get('/admin', mw.adminOnly, (req, res)=>{ }); }); -module.exports = router; +export default router; diff --git a/server/admin.api.spec.js b/server/admin.api.spec.js index b0dbd5d84..6a23393b1 100644 --- a/server/admin.api.spec.js +++ b/server/admin.api.spec.js @@ -1,9 +1,10 @@ -const supertest = require('supertest'); +import supertest from 'supertest'; +import HBApp from './app.js'; +import {model as NotificationModel } from './notifications.model.js'; -const app = supertest.agent(require('app.js').app) - .set('X-Forwarded-Proto', 'https'); -const NotificationModel = require('./notifications.model.js').model; +// Mimic https responses to avoid being redirected all the time +const app = supertest.agent(HBApp).set('X-Forwarded-Proto', 'https'); describe('Tests for admin api', ()=>{ afterEach(()=>{ diff --git a/server/app.js b/server/app.js index 5f3a35150..8a2e17bbd 100644 --- a/server/app.js +++ b/server/app.js @@ -1,25 +1,41 @@ /*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/ // Set working directory to project root +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; +import packageJSON from './../package.json' with { type: "json" }; + +const __dirname = dirname(fileURLToPath(import.meta.url)); process.chdir(`${__dirname}/..`); +const version = packageJSON.version; + +import _ from 'lodash'; +import jwt from 'jwt-simple'; +import express from 'express'; +import yaml from 'js-yaml'; +import config from './config.js'; +import fs from 'fs-extra'; -const _ = require('lodash'); -const jwt = require('jwt-simple'); -const express = require('express'); -const yaml = require('js-yaml'); const app = express(); -const config = require('./config.js'); -const fs = require('fs-extra'); -const { homebrewApi, getBrew, getUsersBrewThemes, getCSS } = require('./homebrew.api.js'); -const GoogleActions = require('./googleActions.js'); -const serveCompressedStaticAssets = require('./static-assets.mv.js'); -const sanitizeFilename = require('sanitize-filename'); -const asyncHandler = require('express-async-handler'); -const templateFn = require('./../client/template.js'); +import api from './homebrew.api.js'; +const { homebrewApi, getBrew, getUsersBrewThemes, getCSS } = api; +import adminApi from './admin.api.js'; +import vaultApi from './vault.api.js'; +import GoogleActions from './googleActions.js'; +import serveCompressedStaticAssets from './static-assets.mv.js'; +import sanitizeFilename from 'sanitize-filename'; +import asyncHandler from 'express-async-handler'; +import templateFn from '../client/template.js'; +import {model as HomebrewModel } from './homebrew.model.js'; -const { DEFAULT_BREW } = require('./brewDefaults.js'); +import { DEFAULT_BREW } from './brewDefaults.js'; +import { splitTextStyleAndMetadata } from '../shared/helpers.js'; -const { splitTextStyleAndMetadata } = require('../shared/helpers.js'); +//==== Middleware Imports ====// +import contentNegotiation from './middleware/content-negotiation.js'; +import bodyParser from 'body-parser'; +import cookieParser from 'cookie-parser'; +import forceSSL from './forcessl.mw.js'; const sanitizeBrew = (brew, accessType)=>{ @@ -34,10 +50,10 @@ const sanitizeBrew = (brew, accessType)=>{ app.set('trust proxy', 1 /* number of proxies between user and server */) app.use('/', serveCompressedStaticAssets(`build`)); -app.use(require('./middleware/content-negotiation.js')); -app.use(require('body-parser').json({ limit: '25mb' })); -app.use(require('cookie-parser')()); -app.use(require('./forcessl.mw.js')); +app.use(contentNegotiation); +app.use(bodyParser.json({ limit: '25mb' })); +app.use(cookieParser()); +app.use(forceSSL); //Account Middleware app.use((req, res, next)=>{ @@ -57,15 +73,14 @@ app.use((req, res, next)=>{ }); app.use(homebrewApi); -app.use(require('./admin.api.js')); -app.use(require('./vault.api.js')); +app.use(adminApi); +app.use(vaultApi); -const HomebrewModel = require('./homebrew.model.js').model; -const welcomeText = require('fs').readFileSync('client/homebrew/pages/homePage/welcome_msg.md', 'utf8'); -const welcomeTextLegacy = require('fs').readFileSync('client/homebrew/pages/homePage/welcome_msg_legacy.md', 'utf8'); -const migrateText = require('fs').readFileSync('client/homebrew/pages/homePage/migrate.md', 'utf8'); -const changelogText = require('fs').readFileSync('changelog.md', 'utf8'); -const faqText = require('fs').readFileSync('faq.md', 'utf8'); +const welcomeText = fs.readFileSync('client/homebrew/pages/homePage/welcome_msg.md', 'utf8'); +const welcomeTextLegacy = fs.readFileSync('client/homebrew/pages/homePage/welcome_msg_legacy.md', 'utf8'); +const migrateText = fs.readFileSync('client/homebrew/pages/homePage/migrate.md', 'utf8'); +const changelogText = fs.readFileSync('changelog.md', 'utf8'); +const faqText = fs.readFileSync('faq.md', 'utf8'); String.prototype.replaceAll = function(s, r){return this.split(s).join(r);}; @@ -479,7 +494,7 @@ const renderPage = async (req, res)=>{ deployment : config.get('heroku_app_name') ?? '' }; const props = { - version : require('./../package.json').version, + version : version, url : req.customUrl || req.originalUrl, brew : req.brew, brews : req.brews, @@ -556,6 +571,4 @@ app.use((req, res)=>{ }); //^=====--------------------------------------=====^// -module.exports = { - app : app -}; +export default app; diff --git a/server/brewDefaults.js b/server/brewDefaults.js index 62fc6e671..11a84b9e9 100644 --- a/server/brewDefaults.js +++ b/server/brewDefaults.js @@ -1,4 +1,4 @@ -const _ = require('lodash'); +import _ from 'lodash'; // Default properties for newly-created brews const DEFAULT_BREW = { @@ -32,7 +32,7 @@ const DEFAULT_BREW_LOAD = _.defaults( }, DEFAULT_BREW); -module.exports = { +export { DEFAULT_BREW, DEFAULT_BREW_LOAD }; diff --git a/server/config.js b/server/config.js index fc50e68ba..69674595b 100644 --- a/server/config.js +++ b/server/config.js @@ -1,5 +1,7 @@ -module.exports = require('nconf') - .argv() - .env({ lowerCase: true }) - .file('environment', { file: `config/${process.env.NODE_ENV}.json` }) - .file('defaults', { file: 'config/default.json' }); +import nconf from 'nconf'; + +export default nconf + .argv() + .env({ lowerCase: true }) + .file('environment', { file: `config/${process.env.NODE_ENV}.json` }) + .file('defaults', { file: 'config/default.json' }); \ No newline at end of file diff --git a/server/db.js b/server/db.js index 7690927e9..97da56a08 100644 --- a/server/db.js +++ b/server/db.js @@ -5,7 +5,7 @@ // reused by both the main application and all tests which require database // connection. -const Mongoose = require('mongoose'); +import Mongoose from 'mongoose'; const getMongoDBURL = (config)=>{ return config.get('mongodb_uri') || @@ -31,7 +31,7 @@ const connect = async (config)=>{ .catch((error)=>handleConnectionError(error)); }; -module.exports = { - connect : connect, - disconnect : disconnect +export default { + connect, + disconnect }; diff --git a/server/forcessl.mw.js b/server/forcessl.mw.js index 4f03d9c32..bf9ab65d3 100644 --- a/server/forcessl.mw.js +++ b/server/forcessl.mw.js @@ -1,4 +1,4 @@ -module.exports = (req, res, next)=>{ +export default (req, res, next)=>{ if(process.env.NODE_ENV === 'local' || process.env.NODE_ENV === 'docker') return next(); if(req.header('x-forwarded-proto') !== 'https') { return res.redirect(302, `https://${req.get('Host')}${req.url}`); diff --git a/server/googleActions.js b/server/googleActions.js index bc97551ee..758cb7e3d 100644 --- a/server/googleActions.js +++ b/server/googleActions.js @@ -1,8 +1,9 @@ /* eslint-disable max-lines */ -const googleDrive = require('@googleapis/drive'); -const { nanoid } = require('nanoid'); -const token = require('./token.js'); -const config = require('./config.js'); +import googleDrive from '@googleapis/drive'; +import { nanoid } from 'nanoid'; +import token from './token.js'; +import config from './config.js'; + let serviceAuth; if(!config.get('service_account')){ @@ -72,7 +73,7 @@ const GoogleActions = { getGoogleFolder : async (auth)=>{ const drive = googleDrive.drive({ version: 'v3', auth }); - fileMetadata = { + const fileMetadata = { 'name' : 'Homebrewery', 'mimeType' : 'application/vnd.google-apps.folder' }; @@ -344,4 +345,4 @@ const GoogleActions = { } }; -module.exports = GoogleActions; +export default GoogleActions; diff --git a/server/homebrew.api.js b/server/homebrew.api.js index e156f3c85..b8d4024ad 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -1,18 +1,20 @@ /* eslint-disable max-lines */ -const _ = require('lodash'); -const HomebrewModel = require('./homebrew.model.js').model; -const router = require('express').Router(); -const zlib = require('zlib'); -const GoogleActions = require('./googleActions.js'); -const Markdown = require('../shared/naturalcrit/markdown.js'); -const yaml = require('js-yaml'); -const asyncHandler = require('express-async-handler'); -const { nanoid } = require('nanoid'); -const { splitTextStyleAndMetadata } = require('../shared/helpers.js'); +import _ from 'lodash'; +import {model as HomebrewModel} from './homebrew.model.js'; +import express from 'express'; +import zlib from 'zlib'; +import GoogleActions from './googleActions.js'; +import Markdown from '../shared/naturalcrit/markdown.js'; +import yaml from 'js-yaml'; +import asyncHandler from 'express-async-handler'; +import { nanoid } from 'nanoid'; +import { splitTextStyleAndMetadata } from '../shared/helpers.js'; +import checkClientVersion from './middleware/check-client-version.js'; -const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); +const router = express.Router(); -const Themes = require('../themes/themes.json'); +import { DEFAULT_BREW, DEFAULT_BREW_LOAD } from './brewDefaults.js'; +import Themes from '../themes/themes.json' with { type: 'json' }; const isStaticTheme = (renderer, themeName)=>{ return Themes[renderer]?.[themeName] !== undefined; @@ -473,7 +475,7 @@ const api = { } }; -router.use('/api', require('./middleware/check-client-version.js')); +router.use('/api', checkClientVersion); router.post('/api', asyncHandler(api.newBrew)); router.put('/api/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); router.put('/api/update/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); @@ -481,4 +483,4 @@ router.delete('/api/:id', asyncHandler(api.deleteBrew)); router.get('/api/remove/:id', asyncHandler(api.deleteBrew)); router.get('/api/theme/:renderer/:id', asyncHandler(api.getThemeBundle)); -module.exports = api; +export default api; \ No newline at end of file diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index a1222cb57..84ffc3052 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -36,8 +36,9 @@ describe('Tests for api', ()=>{ } }); - google = require('./googleActions.js'); - model = require('./homebrew.model.js').model; + google = require('./googleActions.js').default; + model = require('./homebrew.model.js').model; + api = require('./homebrew.api').default; jest.mock('./googleActions.js'); google.authCheck = jest.fn(()=>'client'); @@ -54,8 +55,6 @@ describe('Tests for api', ()=>{ setHeader : jest.fn(()=>{}) }; - api = require('./homebrew.api'); - hbBrew = { text : `brew text`, style : 'hello yes i am css', diff --git a/server/homebrew.model.js b/server/homebrew.model.js index c8db8fdcc..adeac0d5d 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -1,7 +1,8 @@ -const mongoose = require('mongoose'); -const { nanoid } = require('nanoid'); -const _ = require('lodash'); -const zlib = require('zlib'); +import mongoose from 'mongoose'; +import { nanoid } from 'nanoid'; +import _ from 'lodash'; +import zlib from 'zlib'; + const HomebrewSchema = mongoose.Schema({ shareId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } }, @@ -44,7 +45,7 @@ HomebrewSchema.statics.get = async function(query, fields=null){ const brew = await Homebrew.findOne(query, fields).orFail() .catch((error)=>{throw 'Can not find brew';}); if(!_.isNil(brew.textBin)) { // Uncompress zipped text field - unzipped = zlib.inflateRawSync(brew.textBin); + const unzipped = zlib.inflateRawSync(brew.textBin); brew.text = unzipped.toString(); } return brew; @@ -62,7 +63,7 @@ HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, f const Homebrew = mongoose.model('Homebrew', HomebrewSchema); -module.exports = { - schema : HomebrewSchema, - model : Homebrew, +export { + HomebrewSchema as schema, + Homebrew as model }; diff --git a/server/middleware/check-client-version.js b/server/middleware/check-client-version.js index e9caf6eff..001995f4e 100644 --- a/server/middleware/check-client-version.js +++ b/server/middleware/check-client-version.js @@ -1,6 +1,8 @@ -module.exports = (req, res, next)=>{ +import packageJSON from '../../package.json' with { type: "json" }; +const version = packageJSON.version; + +export default (req, res, next)=>{ const userVersion = req.get('Homebrewery-Version'); - const version = require('../../package.json').version; if(userVersion != version) { return res.status(412).send({ diff --git a/server/middleware/content-negotiation.js b/server/middleware/content-negotiation.js index a5bc7dc83..ece60e064 100644 --- a/server/middleware/content-negotiation.js +++ b/server/middleware/content-negotiation.js @@ -1,8 +1,8 @@ -const config = require('../config.js'); +import config from '../config.js'; const nodeEnv = config.get('node_env'); const isLocalEnvironment = config.get('local_environments').includes(nodeEnv); -module.exports = (req, res, next)=>{ +export default (req, res, next)=>{ const isImageRequest = req.get('Accept')?.split(',') ?.filter((h)=>!h.includes('q=')) ?.every((h)=>/image\/.*/.test(h)); diff --git a/server/middleware/content-negotiation.spec.js b/server/middleware/content-negotiation.spec.js deleted file mode 100644 index 68f22eb1c..000000000 --- a/server/middleware/content-negotiation.spec.js +++ /dev/null @@ -1,41 +0,0 @@ -const contentNegotiationMiddleware = require('./content-negotiation.js'); - -describe('content-negotiation-middleware', ()=>{ - let request; - let response; - let next; - - beforeEach(()=>{ - request = { - get : function(key) { - return this[key]; - } - }; - response = { - status : jest.fn(()=>response), - send : jest.fn(()=>{}) - }; - next = jest.fn(); - }); - - it('should return 406 on image request', ()=>{ - contentNegotiationMiddleware({ - Accept : 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', - ...request - }, response); - - expect(response.status).toHaveBeenLastCalledWith(406); - expect(response.send).toHaveBeenCalledWith({ - message : 'Request for image at this URL is not supported' - }); - }); - - it('should call next on non-image request', ()=>{ - contentNegotiationMiddleware({ - Accept : 'text,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', - ...request - }, response, next); - - expect(next).toHaveBeenCalled(); - }); -}); \ No newline at end of file diff --git a/server/notifications.model.js b/server/notifications.model.js index 0a32bde8a..723609bb5 100644 --- a/server/notifications.model.js +++ b/server/notifications.model.js @@ -1,5 +1,5 @@ -const mongoose = require('mongoose'); -const _ = require('lodash'); +import mongoose from 'mongoose'; +import _ from 'lodash'; const NotificationSchema = new mongoose.Schema({ dismissKey : { type: String, unique: true, required: true }, @@ -56,7 +56,7 @@ NotificationSchema.statics.getAll = async function() { const Notification = mongoose.model('Notification', NotificationSchema); -module.exports = { - schema : NotificationSchema, - model : Notification, +export { + NotificationSchema as schema, + Notification as model }; diff --git a/server/static-assets.mv.js b/server/static-assets.mv.js index 732420d46..adf606689 100644 --- a/server/static-assets.mv.js +++ b/server/static-assets.mv.js @@ -1,4 +1,4 @@ -const expressStaticGzip = require('express-static-gzip'); +import expressStaticGzip from 'express-static-gzip'; // Serve brotli-compressed static files if available const customCacheControlHandler=(response, path)=>{ @@ -28,4 +28,4 @@ const init=(pathToAssets)=>{ } }); }; -module.exports = init; +export default init; diff --git a/server/token.js b/server/token.js index 70d6e01c5..7a23dff4b 100644 --- a/server/token.js +++ b/server/token.js @@ -1,7 +1,5 @@ -const jwt = require('jwt-simple'); - -// Load configuration values -const config = require('./config.js'); +import jwt from 'jwt-simple'; +import config from './config.js'; // Generate an Access Token for the given User ID const generateAccessToken = (account)=>{ @@ -24,6 +22,4 @@ const generateAccessToken = (account)=>{ return token; }; -module.exports = { - generateAccessToken : generateAccessToken -}; +export default generateAccessToken; \ No newline at end of file diff --git a/server/vault.api.js b/server/vault.api.js index 8aa382f26..6a7b9fb91 100644 --- a/server/vault.api.js +++ b/server/vault.api.js @@ -1,6 +1,6 @@ -const express = require('express'); -const asyncHandler = require('express-async-handler'); -const HomebrewModel = require('./homebrew.model.js').model; +import express from 'express'; +import asyncHandler from 'express-async-handler'; +import {model as HomebrewModel } from './homebrew.model.js'; const router = express.Router(); @@ -106,4 +106,4 @@ const findTotal = async (req, res)=>{ router.get('/api/vault/total', asyncHandler(findTotal)); router.get('/api/vault', asyncHandler(findBrews)); -module.exports = router; +export default router; diff --git a/shared/helpers.js b/shared/helpers.js index ac684b06f..d60da885d 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -1,6 +1,6 @@ -const _ = require('lodash'); -const yaml = require('js-yaml'); -const request = require('../client/homebrew/utils/request-middleware.js'); +import _ from 'lodash'; +import yaml from 'js-yaml'; +import request from '../client/homebrew/utils/request-middleware.js'; const splitTextStyleAndMetadata = (brew)=>{ brew.text = brew.text.replaceAll('\r\n', '\n'); @@ -51,7 +51,7 @@ const fetchThemeBundle = async (obj, renderer, theme)=>{ })); }; -module.exports = { +export { splitTextStyleAndMetadata, printCurrentBrew, fetchThemeBundle, diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index ef789bdd6..4c1a2f92a 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -1,19 +1,19 @@ /* eslint-disable max-lines */ -const _ = require('lodash'); -const Marked = require('marked'); -const MarkedExtendedTables = require('marked-extended-tables'); -const { markedSmartypantsLite: MarkedSmartypantsLite } = require('marked-smartypants-lite'); -const { gfmHeadingId: MarkedGFMHeadingId, resetHeadings: MarkedGFMResetHeadingIDs } = require('marked-gfm-heading-id'); -const { markedEmoji: MarkedEmojis } = require('marked-emoji'); +import _ from 'lodash'; +import { Parser as MathParser } from 'expr-eval'; +import { marked as Marked } from 'marked'; +import MarkedExtendedTables from 'marked-extended-tables'; +import { markedSmartypantsLite as MarkedSmartypantsLite } from 'marked-smartypants-lite'; +import { gfmHeadingId as MarkedGFMHeadingId, resetHeadings as MarkedGFMResetHeadingIDs } from 'marked-gfm-heading-id'; +import { markedEmoji as MarkedEmojis } from 'marked-emoji'; //Icon fonts included so they can appear in emoji autosuggest dropdown -const diceFont = require('../../themes/fonts/iconFonts/diceFont.js'); -const elderberryInn = require('../../themes/fonts/iconFonts/elderberryInn.js'); -const fontAwesome = require('../../themes/fonts/iconFonts/fontAwesome.js'); -const gameIcons = require('../../themes/fonts/iconFonts/gameIcons.js'); +import diceFont from '../../themes/fonts/iconFonts/diceFont.js'; +import elderberryInn from '../../themes/fonts/iconFonts/elderberryInn.js'; +import gameIcons from '../../themes/fonts/iconFonts/gameIcons.js'; +import fontAwesome from '../../themes/fonts/iconFonts/fontAwesome.js'; -const MathParser = require('expr-eval').Parser; -const renderer = new Marked.Renderer(); +const renderer = new Marked.Renderer(); const tokenizer = new Marked.Tokenizer(); //Limit math features to simple items @@ -854,7 +854,7 @@ const globalVarsList = {}; let varsQueue = []; let globalPageNumber = 0; -module.exports = { +const Markdown = { marked : Marked, render : (rawBrewText, pageNumber=0)=>{ globalVarsList[pageNumber] = {}; //Reset global links for current page, to ensure values are parsed in order @@ -865,6 +865,7 @@ module.exports = { } rawBrewText = rawBrewText.replace(/^\\column$/gm, `\n
\n`); + const opts = Marked.defaults; rawBrewText = opts.hooks.preprocess(rawBrewText); @@ -935,3 +936,6 @@ module.exports = { return errors; }, }; + +export default Markdown; + diff --git a/tests/markdown/basic.test.js b/tests/markdown/basic.test.js index 80f5520e7..e5feec0b3 100644 --- a/tests/markdown/basic.test.js +++ b/tests/markdown/basic.test.js @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; test('Processes the markdown within an HTML block if its just a class wrapper', function() { const source = '
*Bold text*
'; diff --git a/tests/markdown/definition-lists.test.js b/tests/markdown/definition-lists.test.js index 9c0bdf6b0..039754ca1 100644 --- a/tests/markdown/definition-lists.test.js +++ b/tests/markdown/definition-lists.test.js @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; describe('Inline Definition Lists', ()=>{ test('No Term 1 Definition', function() { diff --git a/tests/markdown/emojis.test.js b/tests/markdown/emojis.test.js index a4abbc6a4..e70ebb673 100644 --- a/tests/markdown/emojis.test.js +++ b/tests/markdown/emojis.test.js @@ -1,4 +1,4 @@ -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; const dedent = require('dedent-tabs').default; // Marked.js adds line returns after closing tags on some default tokens. diff --git a/tests/markdown/hard-breaks.test.js b/tests/markdown/hard-breaks.test.js index 3d0f59a41..8af102716 100644 --- a/tests/markdown/hard-breaks.test.js +++ b/tests/markdown/hard-breaks.test.js @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; describe('Hard Breaks', ()=>{ test('Single Break', function() { diff --git a/tests/markdown/mustache-syntax.test.js b/tests/markdown/mustache-syntax.test.js index 51284ef2b..261a5fd32 100644 --- a/tests/markdown/mustache-syntax.test.js +++ b/tests/markdown/mustache-syntax.test.js @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ const dedent = require('dedent-tabs').default; -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; // Marked.js adds line returns after closing tags on some default tokens. // This removes those line returns for comparison sake. diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js index bf778b14d..be16e8a22 100644 --- a/tests/markdown/variables.test.js +++ b/tests/markdown/variables.test.js @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ const dedent = require('dedent-tabs').default; -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; // Marked.js adds line returns after closing tags on some default tokens. // This removes those line returns for comparison sake. diff --git a/tests/routes/static-pages.test.js b/tests/routes/static-pages.test.js index c5578dec9..ebfa48dd4 100644 --- a/tests/routes/static-pages.test.js +++ b/tests/routes/static-pages.test.js @@ -1,8 +1,8 @@ -const supertest = require('supertest'); +import supertest from 'supertest'; +import HBApp from 'app.js'; // Mimic https responses to avoid being redirected all the time -const app = supertest.agent(require('app.js').app) - .set('X-Forwarded-Proto', 'https'); +const app = supertest.agent(HBApp).set('X-Forwarded-Proto', 'https'); describe('Tests for static pages', ()=>{ it('Home page works', ()=>{ diff --git a/themes/V3/Blank/snippets/footer.gen.js b/themes/V3/Blank/snippets/footer.gen.js index 6583cd06e..9384baed7 100644 --- a/themes/V3/Blank/snippets/footer.gen.js +++ b/themes/V3/Blank/snippets/footer.gen.js @@ -1,4 +1,4 @@ -const Markdown = require('../../../../shared/naturalcrit/markdown.js'); +import Markdown from '../../../../shared/naturalcrit/markdown.js'; module.exports = { createFooterFunc : function(headerSize=1){ diff --git a/themes/fonts/iconFonts/diceFont.js b/themes/fonts/iconFonts/diceFont.js index 6ac75ad26..a349d7b0a 100644 --- a/themes/fonts/iconFonts/diceFont.js +++ b/themes/fonts/iconFonts/diceFont.js @@ -93,4 +93,4 @@ const diceFont = { 'df_solid_small_dot_d6_6' : 'df solid-small-dot-d6-6' }; -module.exports = diceFont; \ No newline at end of file +export default diceFont; \ No newline at end of file diff --git a/themes/fonts/iconFonts/elderberryInn.js b/themes/fonts/iconFonts/elderberryInn.js index 042648e4d..6fd933f78 100644 --- a/themes/fonts/iconFonts/elderberryInn.js +++ b/themes/fonts/iconFonts/elderberryInn.js @@ -206,4 +206,4 @@ const elderberryInn = { 'ei_wish' : 'ei wish' }; -module.exports = elderberryInn; \ No newline at end of file +export default elderberryInn; \ No newline at end of file diff --git a/themes/fonts/iconFonts/fontAwesome.js b/themes/fonts/iconFonts/fontAwesome.js index 764bd5bc5..f5f89e3aa 100644 --- a/themes/fonts/iconFonts/fontAwesome.js +++ b/themes/fonts/iconFonts/fontAwesome.js @@ -2051,4 +2051,4 @@ const fontAwesome = { 'fab_zhihu' : 'fab fa-zhihu' }; -module.exports = fontAwesome; \ No newline at end of file +export default fontAwesome; \ No newline at end of file diff --git a/themes/fonts/iconFonts/gameIcons.js b/themes/fonts/iconFonts/gameIcons.js index d92591cef..346e83027 100644 --- a/themes/fonts/iconFonts/gameIcons.js +++ b/themes/fonts/iconFonts/gameIcons.js @@ -506,4 +506,4 @@ const gameIcons = { 'gi_acid' : 'gi acid' }; -module.exports = gameIcons; \ No newline at end of file +export default gameIcons; \ No newline at end of file