diff --git a/babel.config.json b/babel.config.json
new file mode 100644
index 000000000..5e768ec31
--- /dev/null
+++ b/babel.config.json
@@ -0,0 +1,10 @@
+{
+ "presets": [
+ "@babel/preset-env",
+ "@babel/preset-react"
+ ],
+ "plugins": [
+ "@babel/plugin-transform-runtime",
+ "babel-plugin-transform-import-meta"
+ ]
+}
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..6b30e4a73 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,7 +21,7 @@
"cookie-parser": "^1.4.7",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
- "dompurify": "^3.2.0",
+ "dompurify": "^3.2.1",
"expr-eval": "^2.0.2",
"express": "^4.21.1",
"express-async-handler": "^1.2.0",
@@ -39,8 +39,8 @@
"marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
- "mongoose": "^8.8.1",
- "nanoid": "3.3.4",
+ "mongoose": "^8.8.2",
+ "nanoid": "5.0.8",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -52,7 +52,8 @@
},
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.1",
- "eslint": "^9.14.0",
+ "babel-plugin-transform-import-meta": "^2.2.1",
+ "eslint": "^9.15.0",
"eslint-plugin-jest": "^28.9.0",
"eslint-plugin-react": "^7.37.2",
"globals": "^15.12.0",
@@ -559,6 +560,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"
},
@@ -1869,9 +1871,9 @@
}
},
"node_modules/@eslint/config-array": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz",
- "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz",
+ "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==",
"dev": true,
"dependencies": {
"@eslint/object-schema": "^2.1.4",
@@ -1883,20 +1885,19 @@
}
},
"node_modules/@eslint/core": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz",
- "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==",
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz",
+ "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/eslintrc": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
- "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz",
+ "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
@@ -1920,7 +1921,6 @@
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=18"
},
@@ -1929,9 +1929,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.14.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz",
- "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==",
+ "version": "9.15.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz",
+ "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1947,9 +1947,9 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz",
- "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==",
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz",
+ "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==",
"dev": true,
"dependencies": {
"levn": "^0.4.1"
@@ -3082,6 +3082,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "optional": true
+ },
"node_modules/@types/webidl-conversions": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
@@ -3283,7 +3289,6 @@
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
- "license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
@@ -3337,7 +3342,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
- "license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -3881,6 +3885,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",
@@ -4977,11 +5002,10 @@
}
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -5455,9 +5479,12 @@
}
},
"node_modules/dompurify": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.0.tgz",
- "integrity": "sha512-AMdOzK44oFWqHEi0wpOqix/fUNY707OmoeFDnbi3Q5I8uOpy21ufUA5cDJPr0bosxrflOVD/H2DMSvuGKJGfmQ=="
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.1.tgz",
+ "integrity": "sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
},
"node_modules/duplexer2": {
"version": "0.1.4",
@@ -5489,9 +5516,9 @@
"integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw=="
},
"node_modules/elliptic": {
- "version": "6.5.7",
- "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz",
- "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==",
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz",
+ "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==",
"dependencies": {
"bn.js": "^4.11.9",
"brorand": "^1.1.0",
@@ -5761,26 +5788,26 @@
"license": "MIT"
},
"node_modules/eslint": {
- "version": "9.14.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz",
- "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==",
+ "version": "9.15.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz",
+ "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
- "@eslint/config-array": "^0.18.0",
- "@eslint/core": "^0.7.0",
- "@eslint/eslintrc": "^3.1.0",
- "@eslint/js": "9.14.0",
- "@eslint/plugin-kit": "^0.2.0",
+ "@eslint/config-array": "^0.19.0",
+ "@eslint/core": "^0.9.0",
+ "@eslint/eslintrc": "^3.2.0",
+ "@eslint/js": "9.15.0",
+ "@eslint/plugin-kit": "^0.2.3",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
- "@humanwhocodes/retry": "^0.4.0",
+ "@humanwhocodes/retry": "^0.4.1",
"@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
+ "cross-spawn": "^7.0.5",
"debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.2.0",
@@ -5799,8 +5826,7 @@
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "text-table": "^0.2.0"
+ "optionator": "^0.9.3"
},
"bin": {
"eslint": "bin/eslint.js"
@@ -10064,8 +10090,7 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true,
- "license": "MIT"
+ "dev": true
},
"node_modules/json-stable-stringify": {
"version": "0.0.1",
@@ -10866,9 +10891,9 @@
}
},
"node_modules/mongoose": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.1.tgz",
- "integrity": "sha512-l7DgeY1szT98+EKU8GYnga5WnyatAu+kOQ2VlVX1Mxif6A0Umt0YkSiksCiyGxzx8SPhGe9a53ND1GD4yVDrPA==",
+ "version": "8.8.2",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.2.tgz",
+ "integrity": "sha512-jCTSqDANfRzk909v4YoZQi7jlGRB2MTvgG+spVBc/BA4tOs1oWJr//V6yYujqNq9UybpOtsSfBqxI0dSOEFJHQ==",
"dependencies": {
"bson": "^6.7.0",
"kareem": "2.6.3",
@@ -11022,15 +11047,20 @@
"optional": true
},
"node_modules/nanoid": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
- "license": "MIT",
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.8.tgz",
+ "integrity": "sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
"bin": {
- "nanoid": "bin/nanoid.cjs"
+ "nanoid": "bin/nanoid.js"
},
"engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ "node": "^18 || >=20"
}
},
"node_modules/nanomatch": {
@@ -14061,13 +14091,6 @@
"node": ">=8"
}
},
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@@ -14679,7 +14702,6 @@
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
- "license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
diff --git a/package.json b/package.json
index 768303d2f..6211da07f 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"
@@ -57,6 +58,9 @@
"shared",
"server"
],
+ "transformIgnorePatterns": [
+ "node_modules/(?!nanoid/).*"
+ ],
"coveragePathIgnorePatterns": [
"build/*"
],
@@ -78,15 +82,6 @@
"jest-expect-message"
]
},
- "babel": {
- "presets": [
- "@babel/preset-env",
- "@babel/preset-react"
- ],
- "plugins": [
- "@babel/plugin-transform-runtime"
- ]
- },
"dependencies": {
"@babel/core": "^7.26.0",
"@babel/plugin-transform-runtime": "^7.25.9",
@@ -99,7 +94,7 @@
"cookie-parser": "^1.4.7",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
- "dompurify": "^3.2.0",
+ "dompurify": "^3.2.1",
"expr-eval": "^2.0.2",
"express": "^4.21.1",
"express-async-handler": "^1.2.0",
@@ -117,8 +112,8 @@
"marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
- "mongoose": "^8.8.1",
- "nanoid": "3.3.4",
+ "mongoose": "^8.8.2",
+ "nanoid": "5.0.8",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -130,7 +125,8 @@
},
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.1",
- "eslint": "^9.14.0",
+ "babel-plugin-transform-import-meta": "^2.2.1",
+ "eslint": "^9.15.0",
"eslint-plugin-jest": "^28.9.0",
"eslint-plugin-react": "^7.37.2",
"globals": "^15.12.0",
diff --git a/scripts/buildAdmin.js b/scripts/buildAdmin.js
index 1157a063b..9c77315ef 100644
--- a/scripts/buildAdmin.js
+++ b/scripts/buildAdmin.js
@@ -1,13 +1,14 @@
-const fs = require('fs-extra');
-const Proj = require('./project.json');
-const { pack } = require('vitreum');
+import fs from 'fs-extra';
+import Proj from './project.json' with { type: 'json' };
+import vitreum from 'vitreum';
+const { pack } = vitreum;
+
+import lessTransform from 'vitreum/transforms/less.js';
+import assetTransform from 'vitreum/transforms/asset.js';
+
const isDev = !!process.argv.find((arg)=>arg=='--dev');
-const lessTransform = require('vitreum/transforms/less.js');
-const assetTransform = require('vitreum/transforms/asset.js');
-//const Meta = require('vitreum/headtags');
-
const transforms = {
'.less' : lessTransform,
'*' : assetTransform('./build')
@@ -17,7 +18,7 @@ const build = async ({ bundle, render, ssr })=>{
const css = await lessTransform.generate({ paths: './shared' });
await fs.outputFile('./build/admin/bundle.css', css);
await fs.outputFile('./build/admin/bundle.js', bundle);
- await fs.outputFile('./build/admin/ssr.js', ssr);
+ await fs.outputFile('./build/admin/ssr.cjs', ssr);
};
fs.emptyDirSync('./build/admin');
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..ec541e5f5 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')){
@@ -59,7 +60,7 @@ const GoogleActions = {
account.googleRefreshToken = tokens.refresh_token;
}
account.googleAccessToken = tokens.access_token;
- const JWTToken = token.generateAccessToken(account);
+ const JWTToken = token(account);
//Save updated token to cookie
//res.cookie('nc_session', JWTToken, { maxAge: 1000*60*60*24*365, path: '/', sameSite: 'lax' });
@@ -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 9798c60bb..9625a5826 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