diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 58a4de6..e6a3826 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -10,9 +10,11 @@ module.exports = { parserOptions: { tsconfigRootDir: __dirname, project: [ - './tsconfig.json', './tsconfig.test.json', - './tsconfig.frontend.json', + './src/tsconfig.json', + './src/common/tsconfig.json', + './src/assets/ts/tsconfig.json', + './src/assets/views/tsconfig.json', ] }, extends: [ diff --git a/.gitignore b/.gitignore index aa0623f..34df5f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ .idea node_modules -build dist +intermediates public yarn-error.log config/local.* + +tsconfig.tsbuildinfo diff --git a/assets/views/auth/auth.njk b/assets/views/auth/auth.njk deleted file mode 100644 index 9accf33..0000000 --- a/assets/views/auth/auth.njk +++ /dev/null @@ -1,112 +0,0 @@ -{% extends 'layouts/base.njk' %} -{% import 'macros.njk' as macros %} - -{% set title = 'Authentication / Registration' %} -{% set decription = 'Join ' + app.name + ' and share your files!' %} -{% set h1 = 'Authentication and registration' %} - -{% block body %} -
- {% set queryStr = '' %} - {% set previousUrl = getPreviousUrl() %} - {% if query.redirect_uri | length %} - {% set queryStr = '?' + querystring.stringify({redirect_uri: query.redirect_uri}) %} - {% elif previousUrl | length %} - {% set queryStr = '?' + querystring.stringify({redirect_uri: previousUrl}) %} - {% endif %} - -
-

Log in

- - {{ setFormPrefix('login-') }} -
- {{ macros.field(_locals, 'text', 'identifier', query.identifier or '', 'Your email address or username', null, 'required') }} - - {{ macros.field(_locals, 'password', 'password', null, 'Your password', 'Do not fill to log in via magic link.') }} - - {{ macros.field(_locals, 'checkbox', 'persist_session', null, 'Stay logged in on this computer.') }} - - - - {{ macros.csrf(getCsrfToken) }} -
-
- -
-

Register

- - {{ setFormPrefix('register-') }} -
- - {{ macros.csrf(getCsrfToken) }} - - {% if has_username %} - {{ macros.field(_locals, 'text', 'name', null, 'Choose your username', 'This cannot be changed later.', 'pattern="[0-9a-z_-]+" required') }} - {% endif %} - - - - - - {{ macros.field(_locals, 'checkbox', 'terms', null, 'I accept the Terms Of Services.' | safe, null, 'required') }} - - -
-
-
-{% endblock %} - -{% block scripts %} - -{% endblock %} diff --git a/assets/views/macros.njk b/assets/views/macros.njk deleted file mode 100644 index 8857876..0000000 --- a/assets/views/macros.njk +++ /dev/null @@ -1,185 +0,0 @@ -{% macro message(type, content, raw=false, discreet=false) %} -
- - - {{ content|safe if raw else content }} - -
-{% endmacro %} - -{% macro messages(flash) %} - {% set flashed = flash() %} - {% set display = 0 %} - - {% for type, bag in flashed %} - {% if bag|length %} - {% set display = 1 %} - {% endif %} - {% endfor %} - - {% if display %} -
- {% for type, bag in flashed %} - {% for content in bag %} - {{ message(type, content) }} - {% endfor %} - {% endfor %} -
- {% endif %} -{% endmacro %} - -{% macro csrf(getCsrfToken) %} - -{% endmacro %} - -{% macro field(_locals, type, name, value, placeholder, hint, validation_attributes='', extraData='', icon=null) %} - {% set validation = _locals.validation() %} - {% set validation = validation[name] if validation[name] or null %} - {% set previousFormData = _locals.previousFormData() %} - {% set value = previousFormData[name] or value or validation.value or '' %} - {% set prefix = _locals.getFormPrefix() | default('') %} - - {% if type == 'hidden' %} - {% if validation %} - {{ message('error', validation.message) }} - {% endif %} - - {% else %} -
-
- {% if icon != null %} - {% if icon.startsWith('fa') %} - - {% else %} - - {% endif %} - {% endif %} - - {% if type == 'duration' %} -
- {% for f in extraData %} -
- {% if previousFormData[name] %} - {% set v = value[f] %} - {% else %} - {% set v = (value % 60) if f == 's' else (((value - value % 60) / 60 % 60) if f == 'm' else ((value - value % 3600) / 3600 if f == 'h')) %} - {% endif %} - - -
- {% endfor %} -
- {% elseif type == 'select' %} - - - {% elseif type == 'textarea' %} - - {% else %} - - {% endif %} - - -
- - {{ fieldError(_locals, name) }} - {% if hint %} -
{{ hint }}
- {% endif %} -
- {% endif %} -{% endmacro %} - -{% macro fieldError(_locals, name) %} - {% set validation = _locals.validation() %} - {% set validation = validation[name] if validation[name] or null %} - {% if validation %} -
{{ validation.message }}
- {% endif %} -{% endmacro %} - -{% macro websocket(websocketUrl, listener, reconnectOnClose = 1, checkFunction = 0) %} - -{% endmacro %} - -{% macro paginate(pagination, routeName, contextSize) %} - {% if pagination.hasPrevious() or pagination.hasNext() %} - - {% endif %} -{% endmacro %} - -{% macro breadcrumb(currentPageTitle, pages=[]) %} - -{% endmacro %} diff --git a/assets/views/magic_link_lobby.njk b/assets/views/magic_link_lobby.njk deleted file mode 100644 index b86ceb4..0000000 --- a/assets/views/magic_link_lobby.njk +++ /dev/null @@ -1,57 +0,0 @@ -{% extends 'layouts/base.njk' %} - -{% set h1 = 'Authentication lobby' %} -{% set title = app.name + ' ' + h1 %} - -{% block body %} -
-
- {{ macros.message('success', 'We sent a link to ' + email + '. To authenticate, open it from any device.') }} - {{ macros.message('info', 'This link will be valid for and can only be used once.', true, true) }} - -

Waiting for you to open the link...

-
-
-{% endblock %} - -{% block scripts %} - - - {{ macros.websocket(websocketUrl, 'websocketListen', 1, 'isValid') }} -{% endblock %} diff --git a/package.json b/package.json index eb0b6ca..cd1a8ca 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,10 @@ "test": "jest --verbose --runInBand", "clean": "node scripts/clean.js", "prepare-sources": "node scripts/prepare-sources.js", - "compile": "yarn clean && tsc", - "build": "yarn prepare-sources && yarn compile && node . pre-compile-views && node scripts/dist.js", + "compile": "yarn clean && yarn prepare-sources && tsc --build", + "build": "yarn compile && node . pre-compile-views && node scripts/dist.js", "build-production": "NODE_ENV=production yarn build", - "dev": "yarn compile && yarn prepare-sources && concurrently -k -n \"Maildev,Typescript,ViewPreCompile,Node\" -p \"[{name}]\" -c \"yellow,blue,red,green\" \"maildev\" \"tsc --watch\" \"nodemon -i public -i build -- pre-compile-views --watch\" \"nodemon -i public -i build\"", + "dev": "yarn compile && concurrently -k -n \"Maildev,Typescript,ViewPreCompile,Node\" -p \"[{name}]\" -c \"yellow,blue,red,green\" \"maildev\" \"tsc --build --watch\" \"nodemon -i public -i intermediates -- pre-compile-views --watch\" \"nodemon -i public -i intermediates\"", "lint": "eslint .", "release": "yarn build && yarn lint && yarn test && cd dist && yarn publish" }, diff --git a/scripts/_functions.js b/scripts/_functions.js new file mode 100644 index 0000000..f58cda8 --- /dev/null +++ b/scripts/_functions.js @@ -0,0 +1,18 @@ +import fs from "fs"; +import path from "path"; + +export function copyRecursively(file, destination) { + const target = path.join(destination, path.basename(file)); + if (fs.statSync(file).isDirectory()) { + console.log('mkdir', target); + + fs.mkdirSync(target, {recursive: true}); + fs.readdirSync(file).forEach(f => { + copyRecursively(path.join(file, f), target); + }); + } else { + console.log('> cp ', target); + + fs.copyFileSync(file, target); + } +} diff --git a/scripts/clean.js b/scripts/clean.js index 6504ce6..427e651 100644 --- a/scripts/clean.js +++ b/scripts/clean.js @@ -1,7 +1,7 @@ import fs from "fs"; [ - 'build', + 'intermediates', 'dist', 'public', ].forEach(file => { diff --git a/scripts/dist.js b/scripts/dist.js index 25caf83..52722e8 100644 --- a/scripts/dist.js +++ b/scripts/dist.js @@ -1,28 +1,12 @@ import fs from "fs"; import path from "path"; - -function copyRecursively(file, destination) { - const target = path.join(destination, path.basename(file)); - if (fs.statSync(file).isDirectory()) { - console.log('mkdir', target); - - fs.mkdirSync(target, {recursive: true}); - fs.readdirSync(file).forEach(f => { - copyRecursively(path.join(file, f), target); - }); - } else { - console.log('> cp ', target); - - fs.copyFileSync(file, target); - } -} +import {copyRecursively} from "./_functions.js"; [ 'yarn.lock', 'README.md', 'config/', - 'assets/', ].forEach(file => { copyRecursively(file, 'dist'); }); diff --git a/scripts/prepare-sources.js b/scripts/prepare-sources.js index d2ef3f8..92940d1 100644 --- a/scripts/prepare-sources.js +++ b/scripts/prepare-sources.js @@ -1,9 +1,24 @@ import fs from "fs"; +import path from "path"; +import {copyRecursively} from "./_functions.js"; // These folders must exist for nodemon not to loop indefinitely. [ - 'build', 'public', + 'dist', + 'intermediates', + 'intermediates/assets', ].forEach(dir => { if (!fs.existsSync(dir)) fs.mkdirSync(dir); }); + +// Symlink to build/common +const symlink = path.resolve('intermediates/common'); +if (!fs.existsSync(symlink)) { + fs.symlinkSync(path.resolve('dist/common'), symlink); +} + +// Copy all source files +fs.readdirSync('src').forEach(file => { + copyRecursively(path.join('src', file), 'dist'); +}); diff --git a/src/TestApp.ts b/src/TestApp.ts index 1832d43..b66a13b 100644 --- a/src/TestApp.ts +++ b/src/TestApp.ts @@ -84,7 +84,7 @@ export default class TestApp extends Application { this.use(new MaintenanceComponent()); // Dynamic views and routes - const intermediateDirectory = 'build'; + const intermediateDirectory = 'intermediates/assets'; this.use(new FrontendToolsComponent( new AssetCompiler(intermediateDirectory, 'public'), new CopyAssetPreCompiler(intermediateDirectory, '', 'json', ['test/assets'], false), @@ -96,7 +96,7 @@ export default class TestApp extends Application { // Services this.use(new MysqlComponent()); - this.use(new MailComponent(new MailViewEngine('build', 'test/assets'))); + this.use(new MailComponent(new MailViewEngine('intermediates/assets', 'test/assets'))); // Session this.use(new RedisComponent()); diff --git a/assets/package.json b/src/assets/package.json similarity index 100% rename from assets/package.json rename to src/assets/package.json diff --git a/assets/ts/stores.ts b/src/assets/ts/stores.ts similarity index 100% rename from assets/ts/stores.ts rename to src/assets/ts/stores.ts diff --git a/assets/views/auth/account/account.njk b/src/assets/views/auth/account/account.njk similarity index 96% rename from assets/views/auth/account/account.njk rename to src/assets/views/auth/account/account.njk index c4f55dc..1ba9e79 100644 --- a/assets/views/auth/account/account.njk +++ b/src/assets/views/auth/account/account.njk @@ -23,11 +23,11 @@ {% if has_name_component %} - {% include './name_panel.njk' %} + {% include 'views/auth/account/name_panel.njk' %} {% endif %} {% if has_password_component %} - {% include './password_panel.njk' %} + {% include 'views/auth/account/password_panel.njk' %} {% endif %}
diff --git a/assets/views/auth/account/name_panel.njk b/src/assets/views/auth/account/name_panel.njk similarity index 100% rename from assets/views/auth/account/name_panel.njk rename to src/assets/views/auth/account/name_panel.njk diff --git a/assets/views/auth/account/password_panel.njk b/src/assets/views/auth/account/password_panel.njk similarity index 100% rename from assets/views/auth/account/password_panel.njk rename to src/assets/views/auth/account/password_panel.njk diff --git a/assets/views/backend/accounts_approval.njk b/src/assets/views/backend/accounts_approval.njk similarity index 100% rename from assets/views/backend/accounts_approval.njk rename to src/assets/views/backend/accounts_approval.njk diff --git a/assets/views/backend/index.njk b/src/assets/views/backend/index.njk similarity index 100% rename from assets/views/backend/index.njk rename to src/assets/views/backend/index.njk diff --git a/assets/views/errors/400.svelte b/src/assets/views/errors/400.svelte similarity index 100% rename from assets/views/errors/400.svelte rename to src/assets/views/errors/400.svelte diff --git a/assets/views/errors/401.svelte b/src/assets/views/errors/401.svelte similarity index 100% rename from assets/views/errors/401.svelte rename to src/assets/views/errors/401.svelte diff --git a/assets/views/errors/403.svelte b/src/assets/views/errors/403.svelte similarity index 100% rename from assets/views/errors/403.svelte rename to src/assets/views/errors/403.svelte diff --git a/assets/views/errors/404.svelte b/src/assets/views/errors/404.svelte similarity index 100% rename from assets/views/errors/404.svelte rename to src/assets/views/errors/404.svelte diff --git a/assets/views/errors/429.svelte b/src/assets/views/errors/429.svelte similarity index 100% rename from assets/views/errors/429.svelte rename to src/assets/views/errors/429.svelte diff --git a/assets/views/errors/500.svelte b/src/assets/views/errors/500.svelte similarity index 100% rename from assets/views/errors/500.svelte rename to src/assets/views/errors/500.svelte diff --git a/assets/views/errors/503.svelte b/src/assets/views/errors/503.svelte similarity index 100% rename from assets/views/errors/503.svelte rename to src/assets/views/errors/503.svelte diff --git a/assets/views/errors/Error.svelte b/src/assets/views/errors/Error.svelte similarity index 96% rename from assets/views/errors/Error.svelte rename to src/assets/views/errors/Error.svelte index e6f67ce..00248a1 100644 --- a/assets/views/errors/Error.svelte +++ b/src/assets/views/errors/Error.svelte @@ -1,5 +1,5 @@