mirror of
https://github.com/flarum/framework.git
synced 2024-11-24 23:58:26 +08:00
feat: export registry (#3842)
* feat: registry first iteration Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * feat: improve webpack auto export loader Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * chore: remove `compat` API Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * chore: cleanup Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> --------- Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>
This commit is contained in:
parent
cf70865aa6
commit
016503d8c3
|
@ -15,7 +15,7 @@
|
|||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/flags/*": ["../../flags/js/dist-typings/*"]
|
||||
"ext:flarum/flags/*": ["../../flags/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import addFlagsToPosts from './addFlagsToPosts';
|
||||
import addFlagControl from './addFlagControl';
|
||||
import addFlagsDropdown from './addFlagsDropdown';
|
||||
import Flag from './models/Flag';
|
||||
import FlagList from './components/FlagList';
|
||||
import FlagPostModal from './components/FlagPostModal';
|
||||
import FlagsPage from './components/FlagsPage';
|
||||
import FlagsDropdown from './components/FlagsDropdown';
|
||||
|
||||
export default {
|
||||
'flags/addFlagsToPosts': addFlagsToPosts,
|
||||
'flags/addFlagControl': addFlagControl,
|
||||
'flags/addFlagsDropdown': addFlagsDropdown,
|
||||
'flags/models/Flag': Flag,
|
||||
'flags/components/FlagList': FlagList,
|
||||
'flags/components/FlagPostModal': FlagPostModal,
|
||||
'flags/components/FlagsPage': FlagsPage,
|
||||
'flags/components/FlagsDropdown': FlagsDropdown,
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
import app from 'flarum/forum/app';
|
||||
import Page from 'flarum/components/Page';
|
||||
import Page from 'flarum/common/components/Page';
|
||||
|
||||
import FlagList from './FlagList';
|
||||
|
||||
|
|
10
extensions/flags/js/src/forum/forum.ts
Normal file
10
extensions/flags/js/src/forum/forum.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import './addFlagsToPosts';
|
||||
import './addFlagControl';
|
||||
import './addFlagsDropdown';
|
||||
|
||||
import './models/Flag';
|
||||
|
||||
import './components/FlagList';
|
||||
import './components/FlagPostModal';
|
||||
import './components/FlagsPage';
|
||||
import './components/FlagsDropdown';
|
|
@ -15,8 +15,4 @@ app.initializers.add('flarum-flags', () => {
|
|||
addFlagsToPosts();
|
||||
});
|
||||
|
||||
// Expose compat API
|
||||
import flagsCompat from './compat';
|
||||
import { compat } from '@flarum/core/forum';
|
||||
|
||||
Object.assign(compat, flagsCompat);
|
||||
import './forum';
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
// This will output typings to `dist-typings`
|
||||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"]
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,7 @@
|
|||
// This will output typings to `dist-typings`
|
||||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
// TODO: remove after export registry system implemented
|
||||
// Without this, the old-style `@flarum/core` import is resolved to
|
||||
// source code in flarum/core instead of the dist typings.
|
||||
// This causes an inaccurate "duplicate export" error.
|
||||
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,7 @@
|
|||
// This will output typings to `dist-typings`
|
||||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
// TODO: remove after export registry system implemented
|
||||
// Without this, the old-style `@flarum/core` import is resolved to
|
||||
// source code in flarum/core instead of the dist typings.
|
||||
// This causes an inaccurate "duplicate export" error.
|
||||
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import GroupMentionedNotification from './components/GroupMentionedNotification';
|
||||
import MentionsUserPage from './components/MentionsUserPage';
|
||||
import PostMentionedNotification from './components/PostMentionedNotification';
|
||||
import UserMentionedNotification from './components/UserMentionedNotification';
|
||||
import AutocompleteDropdown from './fragments/AutocompleteDropdown';
|
||||
import PostQuoteButton from './fragments/PostQuoteButton';
|
||||
import getCleanDisplayName from './utils/getCleanDisplayName';
|
||||
import getMentionText from './utils/getMentionText';
|
||||
import * as reply from './utils/reply';
|
||||
import selectedText from './utils/selectedText';
|
||||
import * as textFormatter from './utils/textFormatter';
|
||||
import MentionableModel from './mentionables/MentionableModel';
|
||||
import MentionFormat from './mentionables/formats/MentionFormat';
|
||||
import Mentionables from './extenders/Mentionables';
|
||||
|
||||
export default {
|
||||
'mentions/components/MentionsUserPage': MentionsUserPage,
|
||||
'mentions/components/PostMentionedNotification': PostMentionedNotification,
|
||||
'mentions/components/UserMentionedNotification': UserMentionedNotification,
|
||||
'mentions/components/GroupMentionedNotification': GroupMentionedNotification,
|
||||
'mentions/fragments/AutocompleteDropdown': AutocompleteDropdown,
|
||||
'mentions/fragments/PostQuoteButton': PostQuoteButton,
|
||||
'mentions/utils/getCleanDisplayName': getCleanDisplayName,
|
||||
'mentions/utils/getMentionText': getMentionText,
|
||||
'mentions/utils/reply': reply,
|
||||
'mentions/utils/selectedText': selectedText,
|
||||
'mentions/utils/textFormatter': textFormatter,
|
||||
'mentions/mentionables/MentionableModel': MentionableModel,
|
||||
'mentions/mentionables/formats/MentionFormat': MentionFormat,
|
||||
'mentions/extenders/Mentionables': Mentionables,
|
||||
};
|
14
extensions/mentions/js/src/forum/forum.js
Normal file
14
extensions/mentions/js/src/forum/forum.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import './components/GroupMentionedNotification';
|
||||
import './components/MentionsUserPage';
|
||||
import './components/PostMentionedNotification';
|
||||
import './components/UserMentionedNotification';
|
||||
import './fragments/AutocompleteDropdown';
|
||||
import './fragments/PostQuoteButton';
|
||||
import './utils/getCleanDisplayName';
|
||||
import './utils/getMentionText';
|
||||
import './utils/reply';
|
||||
import './utils/selectedText';
|
||||
import './utils/textFormatter';
|
||||
import './mentionables/MentionableModel';
|
||||
import './mentionables/formats/MentionFormat';
|
||||
import './extenders/Mentionables';
|
|
@ -15,8 +15,6 @@ import UserMentionedNotification from './components/UserMentionedNotification';
|
|||
import GroupMentionedNotification from './components/GroupMentionedNotification';
|
||||
import UserPage from 'flarum/forum/components/UserPage';
|
||||
import LinkButton from 'flarum/common/components/LinkButton';
|
||||
import User from 'flarum/common/models/User';
|
||||
import Model from 'flarum/common/Model';
|
||||
|
||||
export { default as extend } from './extend';
|
||||
|
||||
|
@ -90,8 +88,4 @@ app.initializers.add('flarum-mentions', function () {
|
|||
|
||||
export * from './utils/textFormatter';
|
||||
|
||||
// Expose compat API
|
||||
import mentionsCompat from './compat';
|
||||
import { compat } from '@flarum/core/forum';
|
||||
|
||||
Object.assign(compat, mentionsCompat);
|
||||
import './forum';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import app from 'flarum/forum/app';
|
||||
import Badge from 'flarum/common/components/Badge';
|
||||
import highlight from 'flarum/common/helpers/highlight';
|
||||
import type Tag from 'flarum/tags/common/models/Tag';
|
||||
import type Tag from 'ext:flarum/tags/common/models/Tag';
|
||||
import type Mithril from 'mithril';
|
||||
import MentionableModel from './MentionableModel';
|
||||
import type HashMentionFormat from './formats/HashMentionFormat';
|
||||
|
|
|
@ -10,12 +10,7 @@
|
|||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/tags/*": ["../../tags/js/dist-typings/*"],
|
||||
// TODO: remove after export registry system implemented
|
||||
// Without this, the old-style `@flarum/core` import is resolved to
|
||||
// source code in flarum/core instead of the dist typings.
|
||||
// This causes an inaccurate "duplicate export" error.
|
||||
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"ext:flarum/tags/*": ["../../tags/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,7 @@
|
|||
// This will output typings to `dist-typings`
|
||||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
// TODO: remove after export registry system implemented
|
||||
// Without this, the old-style `@flarum/core` import is resolved to
|
||||
// source code in flarum/core instead of the dist typings.
|
||||
// This causes an inaccurate "duplicate export" error.
|
||||
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import IndexPage from 'flarum/forum/components/IndexPage';
|
|||
import Button from 'flarum/common/components/Button';
|
||||
import ItemList from 'flarum/common/utils/ItemList';
|
||||
import type { Children } from 'mithril';
|
||||
import type Tag from 'flarum/tags/common/models/Tag';
|
||||
import type Tag from 'ext:flarum/tags/common/models/Tag';
|
||||
|
||||
export type PusherBinding = {
|
||||
channels: {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/tags/*": ["../../tags/js/dist-typings/*"]
|
||||
"ext:flarum/tags/*": ["../../tags/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,7 @@
|
|||
// This will output typings to `dist-typings`
|
||||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
// TODO: remove after export registry system implemented
|
||||
// Without this, the old-style `@flarum/core` import is resolved to
|
||||
// source code in flarum/core instead of the dist typings.
|
||||
// This causes an inaccurate "duplicate export" error.
|
||||
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
"declarationDir": "./dist-typings",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"flarum/*": ["../vendor/flarum/core/js/dist-typings/*"],
|
||||
"@flarum/core/*": ["../vendor/flarum/core/js/dist-typings/*"]
|
||||
"flarum/*": ["../vendor/flarum/core/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import app from 'flarum/app';
|
||||
import app from 'flarum/admin/app';
|
||||
|
||||
app.initializers.add('flarum-suspend', () => {
|
||||
app.extensionData.for('flarum-suspend').registerPermission(
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import SuspendUserModal from './components/SuspendUserModal';
|
||||
import SuspensionInfoModal from './components/SuspensionInfoModal';
|
||||
import UserSuspendedNotification from './components/UserSuspendedNotification';
|
||||
import UserUnsuspendedNotification from './components/UserUnsuspendedNotification';
|
||||
import checkForSuspension from './checkForSuspension';
|
||||
|
||||
export default {
|
||||
'suspend/components/suspendUserModal': SuspendUserModal,
|
||||
'suspend/components/suspensionInfoModal': SuspensionInfoModal,
|
||||
'suspend/components/UserSuspendedNotification': UserSuspendedNotification,
|
||||
'suspend/components/UserUnsuspendedNotification': UserUnsuspendedNotification,
|
||||
'suspend/checkForSuspension': checkForSuspension,
|
||||
};
|
|
@ -1,10 +1,10 @@
|
|||
import app from 'flarum/forum/app';
|
||||
import Modal from 'flarum/components/Modal';
|
||||
import Button from 'flarum/components/Button';
|
||||
|
||||
import Stream from 'flarum/utils/Stream';
|
||||
import withAttr from 'flarum/utils/withAttr';
|
||||
import Modal from 'flarum/common/components/Modal';
|
||||
import Button from 'flarum/common/components/Button';
|
||||
import Stream from 'flarum/common/utils/Stream';
|
||||
import withAttr from 'flarum/common/utils/withAttr';
|
||||
import ItemList from 'flarum/common/utils/ItemList';
|
||||
|
||||
import { getPermanentSuspensionDate } from '../helpers/suspensionHelper';
|
||||
|
||||
export default class SuspendUserModal extends Modal {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import app from 'flarum/forum/app';
|
||||
import Notification from 'flarum/components/Notification';
|
||||
import Notification from 'flarum/forum/components/Notification';
|
||||
|
||||
import { isPermanentSuspensionDate } from '../helpers/suspensionHelper';
|
||||
|
||||
export default class UserSuspendedNotification extends Notification {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import app from 'flarum/forum/app';
|
||||
import Notification from 'flarum/components/Notification';
|
||||
import Notification from 'flarum/forum/components/Notification';
|
||||
|
||||
export default class UserUnsuspendedNotification extends Notification {
|
||||
icon() {
|
||||
|
|
6
extensions/suspend/js/src/forum/forum.ts
Normal file
6
extensions/suspend/js/src/forum/forum.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import './components/SuspendUserModal';
|
||||
import './components/SuspensionInfoModal';
|
||||
import './components/UserSuspendedNotification';
|
||||
import './components/UserUnsuspendedNotification';
|
||||
|
||||
import './checkForSuspension';
|
|
@ -1,9 +1,9 @@
|
|||
import { extend } from 'flarum/extend';
|
||||
import app from 'flarum/app';
|
||||
import UserControls from 'flarum/utils/UserControls';
|
||||
import Button from 'flarum/components/Button';
|
||||
import Badge from 'flarum/components/Badge';
|
||||
import User from 'flarum/models/User';
|
||||
import { extend } from 'flarum/common/extend';
|
||||
import app from 'flarum/forum/app';
|
||||
import UserControls from 'flarum/forum/utils/UserControls';
|
||||
import Button from 'flarum/common/components/Button';
|
||||
import Badge from 'flarum/common/components/Badge';
|
||||
import User from 'flarum/common/models/User';
|
||||
|
||||
import SuspendUserModal from './components/SuspendUserModal';
|
||||
import UserSuspendedNotification from './components/UserSuspendedNotification';
|
||||
|
@ -42,8 +42,4 @@ app.initializers.add('flarum-suspend', () => {
|
|||
checkForSuspension();
|
||||
});
|
||||
|
||||
// Expose compat API
|
||||
import suspendCompat from './compat';
|
||||
import { compat } from '@flarum/core/forum';
|
||||
|
||||
Object.assign(compat, suspendCompat);
|
||||
import './forum';
|
||||
|
|
|
@ -9,12 +9,7 @@
|
|||
// This will output typings to `dist-typings`
|
||||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
// TODO: remove after export registry system implemented
|
||||
// Without this, the old-style `@flarum/core` import is resolved to
|
||||
// source code in flarum/core instead of the dist typings.
|
||||
// This causes an inaccurate "duplicate export" error.
|
||||
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
9
extensions/tags/js/src/admin/admin.ts
Normal file
9
extensions/tags/js/src/admin/admin.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import '../common/common';
|
||||
|
||||
import './components/TagsPage';
|
||||
import './components/EditTagModal';
|
||||
|
||||
import './addTagsHomePageOption';
|
||||
import './addTagChangePermission';
|
||||
import './addTagPermission';
|
||||
import './addTagsPermissionScope';
|
|
@ -1,17 +0,0 @@
|
|||
import compat from '../common/compat';
|
||||
|
||||
import addTagsHomePageOption from './addTagsHomePageOption';
|
||||
import addTagChangePermission from './addTagChangePermission';
|
||||
import TagsPage from './components/TagsPage';
|
||||
import EditTagModal from './components/EditTagModal';
|
||||
import addTagPermission from './addTagPermission';
|
||||
import addTagsPermissionScope from './addTagsPermissionScope';
|
||||
|
||||
export default Object.assign(compat, {
|
||||
'tags/addTagsHomePageOption': addTagsHomePageOption,
|
||||
'tags/addTagChangePermission': addTagChangePermission,
|
||||
'tags/components/TagsPage': TagsPage,
|
||||
'tags/components/EditTagModal': EditTagModal,
|
||||
'tags/addTagPermission': addTagPermission,
|
||||
'tags/addTagsPermissionScope': addTagsPermissionScope,
|
||||
});
|
|
@ -21,8 +21,4 @@ app.initializers.add('flarum-tags', (app) => {
|
|||
addTagSelectionSettingComponent();
|
||||
});
|
||||
|
||||
// Expose compat API
|
||||
import tagsCompat from './compat';
|
||||
import { compat } from '@flarum/core/admin';
|
||||
|
||||
Object.assign(compat, tagsCompat);
|
||||
import './admin';
|
||||
|
|
11
extensions/tags/js/src/common/common.ts
Normal file
11
extensions/tags/js/src/common/common.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import './utils/sortTags';
|
||||
|
||||
import './models/Tag';
|
||||
|
||||
import './helpers/tagsLabel';
|
||||
import './helpers/tagIcon';
|
||||
import './helpers/tagLabel';
|
||||
|
||||
import './components/TagSelectionModal';
|
||||
|
||||
import './states/TagListState';
|
|
@ -1,17 +0,0 @@
|
|||
import sortTags from './utils/sortTags';
|
||||
import Tag from './models/Tag';
|
||||
import tagsLabel from './helpers/tagsLabel';
|
||||
import tagIcon from './helpers/tagIcon';
|
||||
import tagLabel from './helpers/tagLabel';
|
||||
import TagSelectionModal from './components/TagSelectionModal';
|
||||
import TagListState from './states/TagListState';
|
||||
|
||||
export default {
|
||||
'tags/utils/sortTags': sortTags,
|
||||
'tags/models/Tag': Tag,
|
||||
'tags/helpers/tagsLabel': tagsLabel,
|
||||
'tags/helpers/tagIcon': tagIcon,
|
||||
'tags/helpers/tagLabel': tagLabel,
|
||||
'tags/components/TagSelectionModal': TagSelectionModal,
|
||||
'tags/states/TagListState': TagListState,
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
import compat from '../common/compat';
|
||||
|
||||
import addTagFilter from './addTagFilter';
|
||||
import addTagControl from './addTagControl';
|
||||
import TagHero from './components/TagHero';
|
||||
import TagDiscussionModal from './components/TagDiscussionModal';
|
||||
import TagsPage from './components/TagsPage';
|
||||
import DiscussionTaggedPost from './components/DiscussionTaggedPost';
|
||||
import TagLinkButton from './components/TagLinkButton';
|
||||
import addTagList from './addTagList';
|
||||
import addTagLabels from './addTagLabels';
|
||||
import addTagComposer from './addTagComposer';
|
||||
import getSelectableTags from './utils/getSelectableTags';
|
||||
|
||||
export default Object.assign(compat, {
|
||||
'tags/addTagFilter': addTagFilter,
|
||||
'tags/addTagControl': addTagControl,
|
||||
'tags/components/TagHero': TagHero,
|
||||
'tags/components/TagDiscussionModal': TagDiscussionModal,
|
||||
'tags/components/TagsPage': TagsPage,
|
||||
'tags/components/DiscussionTaggedPost': DiscussionTaggedPost,
|
||||
'tags/components/TagLinkButton': TagLinkButton,
|
||||
'tags/addTagList': addTagList,
|
||||
'tags/addTagLabels': addTagLabels,
|
||||
'tags/addTagComposer': addTagComposer,
|
||||
'tags/utils/getSelectableTags': getSelectableTags,
|
||||
});
|
15
extensions/tags/js/src/forum/forum.ts
Normal file
15
extensions/tags/js/src/forum/forum.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import '../common/common';
|
||||
|
||||
import './utils/getSelectableTags';
|
||||
|
||||
import './components/TagHero';
|
||||
import './components/TagDiscussionModal';
|
||||
import './components/TagsPage';
|
||||
import './components/DiscussionTaggedPost';
|
||||
import './components/TagLinkButton';
|
||||
|
||||
import './addTagFilter';
|
||||
import './addTagControl';
|
||||
import './addTagList';
|
||||
import './addTagLabels';
|
||||
import './addTagComposer';
|
|
@ -20,8 +20,4 @@ app.initializers.add('flarum-tags', function () {
|
|||
addTagComposer();
|
||||
});
|
||||
|
||||
// Expose compat API
|
||||
import tagsCompat from './compat';
|
||||
import { compat } from '@flarum/core/forum';
|
||||
|
||||
Object.assign(compat, tagsCompat);
|
||||
import './forum';
|
||||
|
|
|
@ -9,12 +9,7 @@
|
|||
// This will output typings to `dist-typings`
|
||||
"declarationDir": "./dist-typings",
|
||||
"paths": {
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
// TODO: remove after export registry system implemented
|
||||
// Without this, the old-style `@flarum/core` import is resolved to
|
||||
// source code in flarum/core instead of the dist typings.
|
||||
// This causes an inaccurate "duplicate export" error.
|
||||
"@flarum/core/*": ["../../../framework/core/js/dist-typings/*"],
|
||||
"flarum/*": ["../../../framework/core/js/dist-typings/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
framework/core/js/src/@types/global.d.ts
vendored
2
framework/core/js/src/@types/global.d.ts
vendored
|
@ -98,6 +98,8 @@ interface FlarumObject {
|
|||
* }
|
||||
*/
|
||||
extensions: Readonly<Record<string, ESModule>>;
|
||||
|
||||
reg: any;
|
||||
}
|
||||
|
||||
declare const flarum: FlarumObject;
|
||||
|
|
40
framework/core/js/src/admin/admin.ts
Normal file
40
framework/core/js/src/admin/admin.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import '../common/common';
|
||||
|
||||
import './utils/saveSettings';
|
||||
import './utils/ExtensionData';
|
||||
import './utils/isExtensionEnabled';
|
||||
import './utils/getCategorizedExtensions';
|
||||
import './utils/generateElementId';
|
||||
|
||||
import './components/SettingDropdown';
|
||||
import './components/EditCustomFooterModal';
|
||||
import './components/SessionDropdown';
|
||||
import './components/HeaderPrimary';
|
||||
import './components/AdminPage';
|
||||
import './components/AppearancePage';
|
||||
import './components/StatusWidget';
|
||||
import './components/ExtensionsWidget';
|
||||
import './components/HeaderSecondary';
|
||||
import './components/SettingsModal';
|
||||
import './components/DashboardWidget';
|
||||
import './components/ExtensionPage';
|
||||
import './components/ExtensionLinkButton';
|
||||
import './components/PermissionGrid';
|
||||
import './components/ExtensionPermissionGrid';
|
||||
import './components/MailPage';
|
||||
import './components/UploadImageButton';
|
||||
import './components/LoadingModal';
|
||||
import './components/DashboardPage';
|
||||
import './components/BasicsPage';
|
||||
import './components/UserListPage';
|
||||
import './components/EditCustomHeaderModal';
|
||||
import './components/PermissionsPage';
|
||||
import './components/PermissionDropdown';
|
||||
import './components/AdminNav';
|
||||
import './components/AdminHeader';
|
||||
import './components/EditCustomCssModal';
|
||||
import './components/EditGroupModal';
|
||||
import './components/CreateUserModal';
|
||||
|
||||
import './routes';
|
||||
import './AdminApplication';
|
|
@ -1,77 +0,0 @@
|
|||
import compat from '../common/compat';
|
||||
|
||||
import saveSettings from './utils/saveSettings';
|
||||
import ExtensionData from './utils/ExtensionData';
|
||||
import isExtensionEnabled from './utils/isExtensionEnabled';
|
||||
import getCategorizedExtensions from './utils/getCategorizedExtensions';
|
||||
import SettingDropdown from './components/SettingDropdown';
|
||||
import EditCustomFooterModal from './components/EditCustomFooterModal';
|
||||
import SessionDropdown from './components/SessionDropdown';
|
||||
import HeaderPrimary from './components/HeaderPrimary';
|
||||
import AdminPage from './components/AdminPage';
|
||||
import AppearancePage from './components/AppearancePage';
|
||||
import StatusWidget from './components/StatusWidget';
|
||||
import ExtensionsWidget from './components/ExtensionsWidget';
|
||||
import HeaderSecondary from './components/HeaderSecondary';
|
||||
import SettingsModal from './components/SettingsModal';
|
||||
import DashboardWidget from './components/DashboardWidget';
|
||||
import ExtensionPage from './components/ExtensionPage';
|
||||
import ExtensionLinkButton from './components/ExtensionLinkButton';
|
||||
import PermissionGrid from './components/PermissionGrid';
|
||||
import ExtensionPermissionGrid from './components/ExtensionPermissionGrid';
|
||||
import MailPage from './components/MailPage';
|
||||
import UploadImageButton from './components/UploadImageButton';
|
||||
import LoadingModal from './components/LoadingModal';
|
||||
import DashboardPage from './components/DashboardPage';
|
||||
import BasicsPage from './components/BasicsPage';
|
||||
import UserListPage from './components/UserListPage';
|
||||
import EditCustomHeaderModal from './components/EditCustomHeaderModal';
|
||||
import PermissionsPage from './components/PermissionsPage';
|
||||
import PermissionDropdown from './components/PermissionDropdown';
|
||||
import AdminNav from './components/AdminNav';
|
||||
import AdminHeader from './components/AdminHeader';
|
||||
import EditCustomCssModal from './components/EditCustomCssModal';
|
||||
import EditGroupModal from './components/EditGroupModal';
|
||||
import routes from './routes';
|
||||
import AdminApplication from './AdminApplication';
|
||||
import generateElementId from './utils/generateElementId';
|
||||
import CreateUserModal from './components/CreateUserModal';
|
||||
|
||||
export default Object.assign(compat, {
|
||||
'utils/saveSettings': saveSettings,
|
||||
'utils/ExtensionData': ExtensionData,
|
||||
'utils/isExtensionEnabled': isExtensionEnabled,
|
||||
'utils/getCategorizedExtensions': getCategorizedExtensions,
|
||||
'utils/generateElementId': generateElementId,
|
||||
'components/SettingDropdown': SettingDropdown,
|
||||
'components/EditCustomFooterModal': EditCustomFooterModal,
|
||||
'components/SessionDropdown': SessionDropdown,
|
||||
'components/HeaderPrimary': HeaderPrimary,
|
||||
'components/AdminPage': AdminPage,
|
||||
'components/AppearancePage': AppearancePage,
|
||||
'components/StatusWidget': StatusWidget,
|
||||
'components/ExtensionsWidget': ExtensionsWidget,
|
||||
'components/HeaderSecondary': HeaderSecondary,
|
||||
'components/SettingsModal': SettingsModal,
|
||||
'components/DashboardWidget': DashboardWidget,
|
||||
'components/ExtensionPage': ExtensionPage,
|
||||
'components/ExtensionLinkButton': ExtensionLinkButton,
|
||||
'components/PermissionGrid': PermissionGrid,
|
||||
'components/ExtensionPermissionGrid': ExtensionPermissionGrid,
|
||||
'components/MailPage': MailPage,
|
||||
'components/UploadImageButton': UploadImageButton,
|
||||
'components/LoadingModal': LoadingModal,
|
||||
'components/DashboardPage': DashboardPage,
|
||||
'components/BasicsPage': BasicsPage,
|
||||
'components/UserListPage': UserListPage,
|
||||
'components/EditCustomHeaderModal': EditCustomHeaderModal,
|
||||
'components/PermissionsPage': PermissionsPage,
|
||||
'components/PermissionDropdown': PermissionDropdown,
|
||||
'components/AdminNav': AdminNav,
|
||||
'components/AdminHeader': AdminHeader,
|
||||
'components/EditCustomCssModal': EditCustomCssModal,
|
||||
'components/EditGroupModal': EditGroupModal,
|
||||
'components/CreateUserModal': CreateUserModal,
|
||||
routes: routes,
|
||||
AdminApplication: AdminApplication,
|
||||
});
|
|
@ -2,13 +2,4 @@ import app from './app';
|
|||
|
||||
export { app };
|
||||
|
||||
// Export public API
|
||||
|
||||
// Export compat API
|
||||
import compatObj from './compat';
|
||||
import proxifyCompat from '../common/utils/proxifyCompat';
|
||||
|
||||
// @ts-expect-error The `app` instance needs to be available on compat.
|
||||
compatObj.app = app;
|
||||
|
||||
export const compat = proxifyCompat(compatObj, 'admin');
|
||||
import './admin';
|
||||
|
|
58
framework/core/js/src/common/ExportRegistry.ts
Normal file
58
framework/core/js/src/common/ExportRegistry.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface IExportRegistry {
|
||||
moduleExports: Map<string, Map<string, any>>;
|
||||
onLoads: Map<string, Map<string, Function[]>>;
|
||||
|
||||
/**
|
||||
* Add an instance to the registry.
|
||||
*/
|
||||
add(namespace: string, id: string, object: any): void;
|
||||
|
||||
/**
|
||||
* Add a function to run when object of id "id" is added (or overriden).
|
||||
* If such an object is already registered, the handler will be applied immediately.
|
||||
*/
|
||||
onLoad(namespace: string, id: string, handler: Function): void;
|
||||
|
||||
/**
|
||||
* Retrieve an object of type `id` from the registry.
|
||||
*/
|
||||
get(namespace: string, id: string): any;
|
||||
}
|
||||
|
||||
export default class ExportRegistry implements IExportRegistry {
|
||||
moduleExports = new Map<string, Map<string, any>>();
|
||||
onLoads = new Map<string, Map<string, Function[]>>();
|
||||
|
||||
add(namespace: string, id: string, object: any): void {
|
||||
this.moduleExports.set(namespace, this.moduleExports.get(namespace) || new Map());
|
||||
this.moduleExports.get(namespace)?.set(id, object);
|
||||
|
||||
this.onLoads
|
||||
.get(namespace)
|
||||
?.get(id)
|
||||
?.forEach((handler) => handler(object));
|
||||
}
|
||||
|
||||
onLoad(namespace: string, id: string, handler: Function): void {
|
||||
if (this.moduleExports.has(namespace) && this.moduleExports.get(namespace)?.has(id)) {
|
||||
handler(this.moduleExports.get(namespace)?.get(id));
|
||||
} else {
|
||||
this.onLoads.set(namespace, this.onLoads.get(namespace) || new Map());
|
||||
this.onLoads.get(namespace)?.set(id, this.onLoads.get(namespace)?.get(id) || []);
|
||||
this.onLoads.get(namespace)?.get(id)?.push(handler);
|
||||
}
|
||||
}
|
||||
|
||||
get(namespace: string, id: string): any {
|
||||
const module = this.moduleExports.get(namespace)?.get(id);
|
||||
|
||||
if (!module) {
|
||||
console.warn(`No module found for ${namespace}:${id}`);
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
}
|
89
framework/core/js/src/common/common.ts
Normal file
89
framework/core/js/src/common/common.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
import './extend';
|
||||
import './extenders';
|
||||
|
||||
import './states/PaginatedListState';
|
||||
import './states/AlertManagerState';
|
||||
import './states/ModalManagerState';
|
||||
import './states/PageState';
|
||||
|
||||
import './utils/isObject';
|
||||
import './utils/mixin';
|
||||
import './utils/insertText';
|
||||
import './utils/styleSelectedText';
|
||||
import './utils/Drawer';
|
||||
import './utils/anchorScroll';
|
||||
import './utils/RequestError';
|
||||
import './utils/abbreviateNumber';
|
||||
import './utils/escapeRegExp';
|
||||
import './utils/string';
|
||||
import './utils/throttleDebounce';
|
||||
import './utils/Stream';
|
||||
import './utils/SubtreeRetainer';
|
||||
import './utils/setRouteWithForcedRefresh';
|
||||
import './utils/extract';
|
||||
import './utils/ScrollListener';
|
||||
import './utils/stringToColor';
|
||||
import './utils/subclassOf';
|
||||
import './utils/patchMithril';
|
||||
import './utils/classList';
|
||||
import './utils/extractText';
|
||||
import './utils/formatNumber';
|
||||
import './utils/mapRoutes';
|
||||
import './utils/withAttr';
|
||||
import './utils/focusTrap';
|
||||
import './utils/isDark';
|
||||
import './utils/KeyboardNavigatable';
|
||||
|
||||
import './models/Notification';
|
||||
import './models/User';
|
||||
import './models/Post';
|
||||
import './models/Discussion';
|
||||
import './models/Group';
|
||||
import './models/Forum';
|
||||
|
||||
import './components/AlertManager';
|
||||
import './components/Page';
|
||||
import './components/Switch';
|
||||
import './components/Badge';
|
||||
import './components/LoadingIndicator';
|
||||
import './components/Placeholder';
|
||||
import './components/Separator';
|
||||
import './components/Dropdown';
|
||||
import './components/SplitDropdown';
|
||||
import './components/RequestErrorModal';
|
||||
import './components/FieldSet';
|
||||
import './components/Select';
|
||||
import './components/Navigation';
|
||||
import './components/Alert';
|
||||
import './components/Link';
|
||||
import './components/LinkButton';
|
||||
import './components/Checkbox';
|
||||
import './components/ColorPreviewInput';
|
||||
import './components/SelectDropdown';
|
||||
import './components/ModalManager';
|
||||
import './components/Button';
|
||||
import './components/Modal';
|
||||
import './components/GroupBadge';
|
||||
import './components/TextEditor';
|
||||
import './components/TextEditorButton';
|
||||
import './components/EditUserModal';
|
||||
import './components/Tooltip';
|
||||
|
||||
import './helpers/fullTime';
|
||||
import './helpers/avatar';
|
||||
import './helpers/icon';
|
||||
import './helpers/humanTime';
|
||||
import './helpers/punctuateSeries';
|
||||
import './helpers/highlight';
|
||||
import './helpers/username';
|
||||
import './helpers/userOnline';
|
||||
import './helpers/listItems';
|
||||
import './helpers/textContrastClass';
|
||||
|
||||
import './resolvers/DefaultResolver';
|
||||
|
||||
import './Component';
|
||||
import './Translator';
|
||||
import './Model';
|
||||
import './Application';
|
||||
import './Fragment';
|
|
@ -1,187 +0,0 @@
|
|||
import * as extend from './extend';
|
||||
import extenders from './extenders';
|
||||
import Session from './Session';
|
||||
import Store from './Store';
|
||||
import BasicEditorDriver from './utils/BasicEditorDriver';
|
||||
import evented from './utils/evented';
|
||||
import EventEmitter from './utils/EventEmitter';
|
||||
import KeyboardNavigatable from './utils/KeyboardNavigatable';
|
||||
import liveHumanTimes from './utils/liveHumanTimes';
|
||||
import ItemList from './utils/ItemList';
|
||||
import mixin from './utils/mixin';
|
||||
import humanTime from './utils/humanTime';
|
||||
import computed from './utils/computed';
|
||||
import insertText from './utils/insertText';
|
||||
import styleSelectedText from './utils/styleSelectedText';
|
||||
import Drawer from './utils/Drawer';
|
||||
import anchorScroll from './utils/anchorScroll';
|
||||
import RequestError from './utils/RequestError';
|
||||
import abbreviateNumber from './utils/abbreviateNumber';
|
||||
import escapeRegExp from './utils/escapeRegExp';
|
||||
import * as string from './utils/string';
|
||||
import * as ThrottleDebounce from './utils/throttleDebounce';
|
||||
import Stream from './utils/Stream';
|
||||
import SubtreeRetainer from './utils/SubtreeRetainer';
|
||||
import setRouteWithForcedRefresh from './utils/setRouteWithForcedRefresh';
|
||||
import extract from './utils/extract';
|
||||
import ScrollListener from './utils/ScrollListener';
|
||||
import stringToColor from './utils/stringToColor';
|
||||
import subclassOf from './utils/subclassOf';
|
||||
import patchMithril from './utils/patchMithril';
|
||||
import proxifyCompat from './utils/proxifyCompat';
|
||||
import classList from './utils/classList';
|
||||
import extractText from './utils/extractText';
|
||||
import formatNumber from './utils/formatNumber';
|
||||
import mapRoutes from './utils/mapRoutes';
|
||||
import withAttr from './utils/withAttr';
|
||||
import * as FocusTrap from './utils/focusTrap';
|
||||
import isDark from './utils/isDark';
|
||||
import Notification from './models/Notification';
|
||||
import User from './models/User';
|
||||
import Post from './models/Post';
|
||||
import Discussion from './models/Discussion';
|
||||
import Group from './models/Group';
|
||||
import Forum from './models/Forum';
|
||||
import Component from './Component';
|
||||
import Translator from './Translator';
|
||||
import AlertManager from './components/AlertManager';
|
||||
import Page from './components/Page';
|
||||
import Switch from './components/Switch';
|
||||
import Badge from './components/Badge';
|
||||
import LoadingIndicator from './components/LoadingIndicator';
|
||||
import Placeholder from './components/Placeholder';
|
||||
import Separator from './components/Separator';
|
||||
import Dropdown from './components/Dropdown';
|
||||
import SplitDropdown from './components/SplitDropdown';
|
||||
import RequestErrorModal from './components/RequestErrorModal';
|
||||
import FieldSet from './components/FieldSet';
|
||||
import Select from './components/Select';
|
||||
import Navigation from './components/Navigation';
|
||||
import Alert from './components/Alert';
|
||||
import Link from './components/Link';
|
||||
import LinkButton from './components/LinkButton';
|
||||
import Checkbox from './components/Checkbox';
|
||||
import ColorPreviewInput from './components/ColorPreviewInput';
|
||||
import SelectDropdown from './components/SelectDropdown';
|
||||
import ModalManager from './components/ModalManager';
|
||||
import Button from './components/Button';
|
||||
import Modal from './components/Modal';
|
||||
import GroupBadge from './components/GroupBadge';
|
||||
import TextEditor from './components/TextEditor';
|
||||
import TextEditorButton from './components/TextEditorButton';
|
||||
import EditUserModal from './components/EditUserModal';
|
||||
import Tooltip from './components/Tooltip';
|
||||
import Model from './Model';
|
||||
import Application from './Application';
|
||||
import fullTime from './helpers/fullTime';
|
||||
import avatar from './helpers/avatar';
|
||||
import icon from './helpers/icon';
|
||||
import humanTimeHelper from './helpers/humanTime';
|
||||
import punctuateSeries from './helpers/punctuateSeries';
|
||||
import highlight from './helpers/highlight';
|
||||
import username from './helpers/username';
|
||||
import userOnline from './helpers/userOnline';
|
||||
import listItems from './helpers/listItems';
|
||||
import textContrastClass from './helpers/textContrastClass';
|
||||
import Fragment from './Fragment';
|
||||
import DefaultResolver from './resolvers/DefaultResolver';
|
||||
import PaginatedListState from './states/PaginatedListState';
|
||||
import isObject from './utils/isObject';
|
||||
import AlertManagerState from './states/AlertManagerState';
|
||||
import ModalManagerState from './states/ModalManagerState';
|
||||
import PageState from './states/PageState';
|
||||
|
||||
export default {
|
||||
extenders,
|
||||
extend: extend,
|
||||
Session: Session,
|
||||
Store: Store,
|
||||
'utils/BasicEditorDriver': BasicEditorDriver,
|
||||
'utils/evented': evented,
|
||||
'utils/EventEmitter': EventEmitter,
|
||||
'utils/KeyboardNavigatable': KeyboardNavigatable,
|
||||
'utils/liveHumanTimes': liveHumanTimes,
|
||||
'utils/ItemList': ItemList,
|
||||
'utils/mixin': mixin,
|
||||
'utils/humanTime': humanTime,
|
||||
'utils/computed': computed,
|
||||
'utils/insertText': insertText,
|
||||
'utils/styleSelectedText': styleSelectedText,
|
||||
'utils/Drawer': Drawer,
|
||||
'utils/anchorScroll': anchorScroll,
|
||||
'utils/RequestError': RequestError,
|
||||
'utils/abbreviateNumber': abbreviateNumber,
|
||||
'utils/string': string,
|
||||
'utils/SubtreeRetainer': SubtreeRetainer,
|
||||
'utils/escapeRegExp': escapeRegExp,
|
||||
'utils/extract': extract,
|
||||
'utils/ScrollListener': ScrollListener,
|
||||
'utils/stringToColor': stringToColor,
|
||||
'utils/Stream': Stream,
|
||||
'utils/subclassOf': subclassOf,
|
||||
'utils/setRouteWithForcedRefresh': setRouteWithForcedRefresh,
|
||||
'utils/patchMithril': patchMithril,
|
||||
'utils/proxifyCompat': proxifyCompat,
|
||||
'utils/classList': classList,
|
||||
'utils/extractText': extractText,
|
||||
'utils/formatNumber': formatNumber,
|
||||
'utils/mapRoutes': mapRoutes,
|
||||
'utils/withAttr': withAttr,
|
||||
'utils/throttleDebounce': ThrottleDebounce,
|
||||
'utils/isObject': isObject,
|
||||
'utils/focusTrap': FocusTrap,
|
||||
'utils/isDark': isDark,
|
||||
'models/Notification': Notification,
|
||||
'models/User': User,
|
||||
'models/Post': Post,
|
||||
'models/Discussion': Discussion,
|
||||
'models/Group': Group,
|
||||
'models/Forum': Forum,
|
||||
Component: Component,
|
||||
Fragment: Fragment,
|
||||
Translator: Translator,
|
||||
'components/AlertManager': AlertManager,
|
||||
'components/Page': Page,
|
||||
'components/Switch': Switch,
|
||||
'components/Badge': Badge,
|
||||
'components/LoadingIndicator': LoadingIndicator,
|
||||
'components/Placeholder': Placeholder,
|
||||
'components/Separator': Separator,
|
||||
'components/Dropdown': Dropdown,
|
||||
'components/SplitDropdown': SplitDropdown,
|
||||
'components/RequestErrorModal': RequestErrorModal,
|
||||
'components/FieldSet': FieldSet,
|
||||
'components/Select': Select,
|
||||
'components/Navigation': Navigation,
|
||||
'components/Alert': Alert,
|
||||
'components/Link': Link,
|
||||
'components/LinkButton': LinkButton,
|
||||
'components/Checkbox': Checkbox,
|
||||
'components/ColorPreviewInput': ColorPreviewInput,
|
||||
'components/SelectDropdown': SelectDropdown,
|
||||
'components/ModalManager': ModalManager,
|
||||
'components/Button': Button,
|
||||
'components/Modal': Modal,
|
||||
'components/GroupBadge': GroupBadge,
|
||||
'components/TextEditor': TextEditor,
|
||||
'components/TextEditorButton': TextEditorButton,
|
||||
'components/Tooltip': Tooltip,
|
||||
'components/EditUserModal': EditUserModal,
|
||||
Model: Model,
|
||||
Application: Application,
|
||||
'helpers/fullTime': fullTime,
|
||||
'helpers/avatar': avatar,
|
||||
'helpers/icon': icon,
|
||||
'helpers/humanTime': humanTimeHelper,
|
||||
'helpers/punctuateSeries': punctuateSeries,
|
||||
'helpers/highlight': highlight,
|
||||
'helpers/username': username,
|
||||
'helpers/userOnline': userOnline,
|
||||
'helpers/listItems': listItems,
|
||||
'helpers/textContrastClass': textContrastClass,
|
||||
'resolvers/DefaultResolver': DefaultResolver,
|
||||
'states/PaginatedListState': PaginatedListState,
|
||||
'states/AlertManagerState': AlertManagerState,
|
||||
'states/ModalManagerState': ModalManagerState,
|
||||
'states/PageState': PageState,
|
||||
};
|
|
@ -3,9 +3,11 @@ import PostTypes from './PostTypes';
|
|||
import Routes from './Routes';
|
||||
import Store from './Store';
|
||||
|
||||
export default {
|
||||
const extenders = {
|
||||
Model,
|
||||
PostTypes,
|
||||
Routes,
|
||||
Store,
|
||||
};
|
||||
|
||||
export default extenders;
|
||||
|
|
|
@ -15,6 +15,8 @@ import localizedFormat from 'dayjs/plugin/localizedFormat';
|
|||
dayjs.extend(relativeTime);
|
||||
dayjs.extend(localizedFormat);
|
||||
|
||||
import './registry';
|
||||
|
||||
import patchMithril from './utils/patchMithril';
|
||||
|
||||
patchMithril(window);
|
||||
|
|
3
framework/core/js/src/common/registry.ts
Normal file
3
framework/core/js/src/common/registry.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import ExportRegistry from './ExportRegistry';
|
||||
|
||||
flarum.reg = new ExportRegistry();
|
|
@ -1,12 +0,0 @@
|
|||
export default function proxifyCompat(compat: Record<string, unknown>, namespace: string) {
|
||||
// regex to replace common/ and NAMESPACE/ for core & core extensions
|
||||
// and remove .js, .ts and .tsx extensions
|
||||
// e.g. admin/utils/extract --> utils/extract
|
||||
// e.g. tags/common/utils/sortTags --> tags/utils/sortTags
|
||||
const regex = new RegExp(String.raw`(\w+\/)?(${namespace}|common)\/`);
|
||||
const fileExt = /(\.js|\.tsx?)$/;
|
||||
|
||||
return new Proxy(compat, {
|
||||
get: (obj, prop: string) => obj[prop] || obj[prop.replace(regex, '$1').replace(fileExt, '')],
|
||||
});
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
// Re-exports `throttle-debounce` to be used in `compat.js`.
|
||||
// Re-exports `throttle-debounce` to be added in the export registry.
|
||||
|
||||
export { throttle, debounce } from 'throttle-debounce';
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
* Replaces m.withAttr for Mithril 2.0.
|
||||
* @see https://mithril.js.org/archive/v0.2.5/mithril.withAttr.html
|
||||
*/
|
||||
export default (key: string, cb: Function) =>
|
||||
function (this: Element) {
|
||||
export default function withAttr(key: string, cb: Function) {
|
||||
return function (this: Element) {
|
||||
cb(this.getAttribute(key) || (this as any)[key]);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
import compat from '../common/compat';
|
||||
|
||||
import PostControls from './utils/PostControls';
|
||||
import KeyboardNavigatable from '../common/utils/KeyboardNavigatable';
|
||||
import slidable from './utils/slidable';
|
||||
import History from './utils/History';
|
||||
import DiscussionControls from './utils/DiscussionControls';
|
||||
import alertEmailConfirmation from './utils/alertEmailConfirmation';
|
||||
import UserControls from './utils/UserControls';
|
||||
import Pane from './utils/Pane';
|
||||
import ComposerState from './states/ComposerState';
|
||||
import DiscussionListState from './states/DiscussionListState';
|
||||
import GlobalSearchState from './states/GlobalSearchState';
|
||||
import NotificationListState from './states/NotificationListState';
|
||||
import PostStreamState from './states/PostStreamState';
|
||||
import SearchState from './states/SearchState';
|
||||
import UserSecurityPageState from './states/UserSecurityPageState';
|
||||
import AffixedSidebar from './components/AffixedSidebar';
|
||||
import DiscussionPage from './components/DiscussionPage';
|
||||
import DiscussionListPane from './components/DiscussionListPane';
|
||||
import LogInModal from './components/LogInModal';
|
||||
import ComposerBody from './components/ComposerBody';
|
||||
import ForgotPasswordModal from './components/ForgotPasswordModal';
|
||||
import Notification from './components/Notification';
|
||||
import LogInButton from './components/LogInButton';
|
||||
import DiscussionsUserPage from './components/DiscussionsUserPage';
|
||||
import Composer from './components/Composer';
|
||||
import SessionDropdown from './components/SessionDropdown';
|
||||
import HeaderPrimary from './components/HeaderPrimary';
|
||||
import PostEdited from './components/PostEdited';
|
||||
import PostStream from './components/PostStream';
|
||||
import ChangePasswordModal from './components/ChangePasswordModal';
|
||||
import IndexPage from './components/IndexPage';
|
||||
import DiscussionRenamedNotification from './components/DiscussionRenamedNotification';
|
||||
import DiscussionsSearchSource from './components/DiscussionsSearchSource';
|
||||
import HeaderSecondary from './components/HeaderSecondary';
|
||||
import ComposerButton from './components/ComposerButton';
|
||||
import DiscussionList from './components/DiscussionList';
|
||||
import ReplyPlaceholder from './components/ReplyPlaceholder';
|
||||
import AvatarEditor from './components/AvatarEditor';
|
||||
import Post from './components/Post';
|
||||
import SettingsPage from './components/SettingsPage';
|
||||
import TerminalPost from './components/TerminalPost';
|
||||
import ChangeEmailModal from './components/ChangeEmailModal';
|
||||
import NotificationsDropdown from './components/NotificationsDropdown';
|
||||
import UserPage from './components/UserPage';
|
||||
import PostUser from './components/PostUser';
|
||||
import UserCard from './components/UserCard';
|
||||
import UsersSearchSource from './components/UsersSearchSource';
|
||||
import UserSecurityPage from './components/UserSecurityPage';
|
||||
import NotificationGrid from './components/NotificationGrid';
|
||||
import PostPreview from './components/PostPreview';
|
||||
import EventPost from './components/EventPost';
|
||||
import DiscussionHero from './components/DiscussionHero';
|
||||
import PostMeta from './components/PostMeta';
|
||||
import DiscussionRenamedPost from './components/DiscussionRenamedPost';
|
||||
import DiscussionComposer from './components/DiscussionComposer';
|
||||
import LogInButtons from './components/LogInButtons';
|
||||
import NotificationList from './components/NotificationList';
|
||||
import WelcomeHero from './components/WelcomeHero';
|
||||
import SignUpModal from './components/SignUpModal';
|
||||
import CommentPost from './components/CommentPost';
|
||||
import ComposerPostPreview from './components/ComposerPostPreview';
|
||||
import ReplyComposer from './components/ReplyComposer';
|
||||
import NotificationsPage from './components/NotificationsPage';
|
||||
import PostStreamScrubber from './components/PostStreamScrubber';
|
||||
import EditPostComposer from './components/EditPostComposer';
|
||||
import RenameDiscussionModal from './components/RenameDiscussionModal';
|
||||
import Search from './components/Search';
|
||||
import DiscussionListItem from './components/DiscussionListItem';
|
||||
import LoadingPost from './components/LoadingPost';
|
||||
import PostsUserPage from './components/PostsUserPage';
|
||||
import DiscussionPageResolver from './resolvers/DiscussionPageResolver';
|
||||
import BasicEditorDriver from '../common/utils/BasicEditorDriver';
|
||||
import routes from './routes';
|
||||
import ForumApplication from './ForumApplication';
|
||||
import isSafariMobile from './utils/isSafariMobile';
|
||||
|
||||
export default Object.assign(compat, {
|
||||
'utils/PostControls': PostControls,
|
||||
// @deprecated import from 'flarum/common/utils/KeyboardNavigatable' instead
|
||||
'utils/KeyboardNavigatable': KeyboardNavigatable,
|
||||
'utils/slidable': slidable,
|
||||
'utils/History': History,
|
||||
'utils/DiscussionControls': DiscussionControls,
|
||||
'utils/alertEmailConfirmation': alertEmailConfirmation,
|
||||
'utils/UserControls': UserControls,
|
||||
'utils/Pane': Pane,
|
||||
'utils/BasicEditorDriver': BasicEditorDriver,
|
||||
'utils/isSafariMobile': isSafariMobile,
|
||||
'states/ComposerState': ComposerState,
|
||||
'states/DiscussionListState': DiscussionListState,
|
||||
'states/GlobalSearchState': GlobalSearchState,
|
||||
'states/NotificationListState': NotificationListState,
|
||||
'states/PostStreamState': PostStreamState,
|
||||
'states/SearchState': SearchState,
|
||||
'states/UserSecurityPageState': UserSecurityPageState,
|
||||
'components/AffixedSidebar': AffixedSidebar,
|
||||
'components/DiscussionPage': DiscussionPage,
|
||||
'components/DiscussionListPane': DiscussionListPane,
|
||||
'components/LogInModal': LogInModal,
|
||||
'components/ComposerBody': ComposerBody,
|
||||
'components/ForgotPasswordModal': ForgotPasswordModal,
|
||||
'components/Notification': Notification,
|
||||
'components/LogInButton': LogInButton,
|
||||
'components/DiscussionsUserPage': DiscussionsUserPage,
|
||||
'components/Composer': Composer,
|
||||
'components/SessionDropdown': SessionDropdown,
|
||||
'components/HeaderPrimary': HeaderPrimary,
|
||||
'components/PostEdited': PostEdited,
|
||||
'components/PostStream': PostStream,
|
||||
'components/ChangePasswordModal': ChangePasswordModal,
|
||||
'components/IndexPage': IndexPage,
|
||||
'components/DiscussionRenamedNotification': DiscussionRenamedNotification,
|
||||
'components/DiscussionsSearchSource': DiscussionsSearchSource,
|
||||
'components/HeaderSecondary': HeaderSecondary,
|
||||
'components/ComposerButton': ComposerButton,
|
||||
'components/DiscussionList': DiscussionList,
|
||||
'components/ReplyPlaceholder': ReplyPlaceholder,
|
||||
'components/AvatarEditor': AvatarEditor,
|
||||
'components/Post': Post,
|
||||
'components/SettingsPage': SettingsPage,
|
||||
'components/TerminalPost': TerminalPost,
|
||||
'components/ChangeEmailModal': ChangeEmailModal,
|
||||
'components/NotificationsDropdown': NotificationsDropdown,
|
||||
'components/UserPage': UserPage,
|
||||
'components/PostUser': PostUser,
|
||||
'components/UserCard': UserCard,
|
||||
'components/UsersSearchSource': UsersSearchSource,
|
||||
'components/UserSecurityPage': UserSecurityPage,
|
||||
'components/NotificationGrid': NotificationGrid,
|
||||
'components/PostPreview': PostPreview,
|
||||
'components/EventPost': EventPost,
|
||||
'components/DiscussionHero': DiscussionHero,
|
||||
'components/PostMeta': PostMeta,
|
||||
'components/DiscussionRenamedPost': DiscussionRenamedPost,
|
||||
'components/DiscussionComposer': DiscussionComposer,
|
||||
'components/LogInButtons': LogInButtons,
|
||||
'components/NotificationList': NotificationList,
|
||||
'components/WelcomeHero': WelcomeHero,
|
||||
'components/SignUpModal': SignUpModal,
|
||||
'components/CommentPost': CommentPost,
|
||||
'components/ComposerPostPreview': ComposerPostPreview,
|
||||
'components/ReplyComposer': ReplyComposer,
|
||||
'components/NotificationsPage': NotificationsPage,
|
||||
'components/PostStreamScrubber': PostStreamScrubber,
|
||||
'components/EditPostComposer': EditPostComposer,
|
||||
'components/RenameDiscussionModal': RenameDiscussionModal,
|
||||
'components/Search': Search,
|
||||
'components/DiscussionListItem': DiscussionListItem,
|
||||
'components/LoadingPost': LoadingPost,
|
||||
'components/PostsUserPage': PostsUserPage,
|
||||
'resolvers/DiscussionPageResolver': DiscussionPageResolver,
|
||||
routes: routes,
|
||||
ForumApplication: ForumApplication,
|
||||
});
|
75
framework/core/js/src/forum/forum.ts
Normal file
75
framework/core/js/src/forum/forum.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import '../common/common';
|
||||
import '../common/utils/BasicEditorDriver';
|
||||
|
||||
import './utils/PostControls';
|
||||
import './utils/slidable';
|
||||
import './utils/History';
|
||||
import './utils/DiscussionControls';
|
||||
import './utils/alertEmailConfirmation';
|
||||
import './utils/UserControls';
|
||||
import './utils/Pane';
|
||||
import './states/ComposerState';
|
||||
import './states/DiscussionListState';
|
||||
import './states/GlobalSearchState';
|
||||
import './states/NotificationListState';
|
||||
import './states/PostStreamState';
|
||||
import './states/SearchState';
|
||||
import './states/UserSecurityPageState';
|
||||
import './components/AffixedSidebar';
|
||||
import './components/DiscussionPage';
|
||||
import './components/DiscussionListPane';
|
||||
import './components/LogInModal';
|
||||
import './components/ComposerBody';
|
||||
import './components/ForgotPasswordModal';
|
||||
import './components/Notification';
|
||||
import './components/LogInButton';
|
||||
import './components/DiscussionsUserPage';
|
||||
import './components/Composer';
|
||||
import './components/SessionDropdown';
|
||||
import './components/HeaderPrimary';
|
||||
import './components/PostEdited';
|
||||
import './components/PostStream';
|
||||
import './components/ChangePasswordModal';
|
||||
import './components/IndexPage';
|
||||
import './components/DiscussionRenamedNotification';
|
||||
import './components/DiscussionsSearchSource';
|
||||
import './components/HeaderSecondary';
|
||||
import './components/ComposerButton';
|
||||
import './components/DiscussionList';
|
||||
import './components/ReplyPlaceholder';
|
||||
import './components/AvatarEditor';
|
||||
import './components/Post';
|
||||
import './components/SettingsPage';
|
||||
import './components/TerminalPost';
|
||||
import './components/ChangeEmailModal';
|
||||
import './components/NotificationsDropdown';
|
||||
import './components/UserPage';
|
||||
import './components/PostUser';
|
||||
import './components/UserCard';
|
||||
import './components/UsersSearchSource';
|
||||
import './components/UserSecurityPage';
|
||||
import './components/NotificationGrid';
|
||||
import './components/PostPreview';
|
||||
import './components/EventPost';
|
||||
import './components/DiscussionHero';
|
||||
import './components/PostMeta';
|
||||
import './components/DiscussionRenamedPost';
|
||||
import './components/DiscussionComposer';
|
||||
import './components/LogInButtons';
|
||||
import './components/NotificationList';
|
||||
import './components/WelcomeHero';
|
||||
import './components/SignUpModal';
|
||||
import './components/CommentPost';
|
||||
import './components/ComposerPostPreview';
|
||||
import './components/ReplyComposer';
|
||||
import './components/NotificationsPage';
|
||||
import './components/PostStreamScrubber';
|
||||
import './components/EditPostComposer';
|
||||
import './components/RenameDiscussionModal';
|
||||
import './components/Search';
|
||||
import './components/DiscussionListItem';
|
||||
import './components/LoadingPost';
|
||||
import './components/PostsUserPage';
|
||||
import './resolvers/DiscussionPageResolver';
|
||||
import './routes';
|
||||
import './ForumApplication';
|
|
@ -6,11 +6,4 @@ import app from './app';
|
|||
|
||||
export { app };
|
||||
|
||||
// Export compat API
|
||||
import compatObj from './compat';
|
||||
import proxifyCompat from '../common/utils/proxifyCompat';
|
||||
|
||||
// @ts-ignore
|
||||
compatObj.app = app;
|
||||
|
||||
export const compat = proxifyCompat(compatObj, 'forum');
|
||||
import './forum';
|
||||
|
|
|
@ -12,7 +12,7 @@ import extractText from '../../common/utils/extractText';
|
|||
* The `DiscussionControls` utility constructs a list of buttons for a
|
||||
* discussion which perform actions on it.
|
||||
*/
|
||||
export default {
|
||||
const DiscussionControls = {
|
||||
/**
|
||||
* Get a list of controls for a discussion.
|
||||
*
|
||||
|
@ -240,3 +240,5 @@ export default {
|
|||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default DiscussionControls;
|
||||
|
|
|
@ -9,7 +9,7 @@ import extractText from '../../common/utils/extractText';
|
|||
* The `PostControls` utility constructs a list of buttons for a post which
|
||||
* perform actions on it.
|
||||
*/
|
||||
export default {
|
||||
const PostControls = {
|
||||
/**
|
||||
* Get a list of controls for a post.
|
||||
*
|
||||
|
@ -183,3 +183,5 @@ export default {
|
|||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default PostControls;
|
||||
|
|
|
@ -9,7 +9,7 @@ import ItemList from '../../common/utils/ItemList';
|
|||
* The `UserControls` utility constructs a list of buttons for a user which
|
||||
* perform actions on it.
|
||||
*/
|
||||
export default {
|
||||
const UserControls = {
|
||||
/**
|
||||
* Get a list of controls for a user.
|
||||
*
|
||||
|
@ -146,3 +146,5 @@ export default {
|
|||
app.modal.show(EditUserModal, { user });
|
||||
},
|
||||
};
|
||||
|
||||
export default UserControls;
|
||||
|
|
|
@ -40,7 +40,7 @@ class AddTranslations
|
|||
$sources->addString(function () use ($locale) {
|
||||
$translations = $this->getTranslations($locale);
|
||||
|
||||
return 'flarum.core.app.translator.addTranslations('.json_encode($translations).')';
|
||||
return 'app.translator.addTranslations('.json_encode($translations).')';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
document.getElementById('flarum-loading').style.display = 'none';
|
||||
|
||||
try {
|
||||
flarum.core.app.load(data);
|
||||
flarum.core.app.bootExtensions(flarum.extensions);
|
||||
flarum.core.app.boot();
|
||||
app.load(data);
|
||||
app.bootExtensions(flarum.extensions);
|
||||
app.boot();
|
||||
} catch (e) {
|
||||
var error = document.getElementById('flarum-loading-error');
|
||||
error.innerHTML += document.getElementById('flarum-content').textContent;
|
||||
|
|
|
@ -6,7 +6,7 @@ module.exports = (options = {}) => ({
|
|||
transform: {
|
||||
'^.+\\.[tj]sx?$': [
|
||||
'babel-jest',
|
||||
require('flarum-webpack-config/babel.config.js'),
|
||||
require('flarum-webpack-config/babel.config.cjs'),
|
||||
],
|
||||
'^.+\\.tsx?$': [
|
||||
'ts-jest',
|
||||
|
|
|
@ -31,27 +31,3 @@ Add another build script to your `package.json` like the one below:
|
|||
You'll need to configure a `tsconfig.json` file to ensure your IDE sets up Typescript support correctly.
|
||||
|
||||
For details about this, see the [`flarum/flarum-tsconfig` repository](https://github.com/flarum/flarum-tsconfig)
|
||||
|
||||
## Options
|
||||
|
||||
### `useExtensions`
|
||||
|
||||
`Array<string>`, defaults to `[]`.
|
||||
|
||||
An array of extensions whose modules should be made available. This is a shortcut to add [`externals`](https://webpack.js.org/configuration/externals/) configuration for extension modules. Imported extension modules will not be bundled, but will instead refer to the extension's exports included in the Flarum runtime (ie. `flarum.extensions["vendor/package"]`).
|
||||
|
||||
For example, to access the Tags extension module within your extension:
|
||||
|
||||
**forum.js**
|
||||
|
||||
```js
|
||||
import { Tag } from '@flarum/tags/forum';
|
||||
```
|
||||
|
||||
**webpack.config.js**
|
||||
|
||||
```js
|
||||
module.exports = config({
|
||||
useExtensions: ['flarum/tags'],
|
||||
});
|
||||
```
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"name": "flarum-webpack-config",
|
||||
"type": "module",
|
||||
"version": "2.0.2",
|
||||
"description": "Webpack config for Flarum JS and TS transpilation.",
|
||||
"main": "index.js",
|
||||
"main": "src/index.cjs",
|
||||
"author": "Flarum Team",
|
||||
"license": "MIT",
|
||||
"prettier": "@flarum/prettier-config",
|
||||
|
@ -21,13 +22,18 @@
|
|||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/runtime": "^7.20.1",
|
||||
"babel-loader": "^9.1.0",
|
||||
"loader-utils": "^1.4.0",
|
||||
"schema-utils": "^3.0.0",
|
||||
"typescript": "^4.9.3",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-bundle-analyzer": "^4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.8.0",
|
||||
"@flarum/prettier-config": "^1.0.0"
|
||||
"@flarum/prettier-config": "^1.0.0",
|
||||
"babel-jest": "^29.5.0",
|
||||
"jest": "^29.5.0",
|
||||
"memfs": "^3.5.3",
|
||||
"prettier": "^2.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "echo 'skipping..'",
|
||||
|
@ -39,6 +45,10 @@
|
|||
"build-typings": "echo 'skipping..'",
|
||||
"post-build-typings": "echo 'skipping..'",
|
||||
"check-typings": "echo 'skipping..'",
|
||||
"check-typings-coverage": "echo 'skipping..'"
|
||||
"check-typings-coverage": "echo 'skipping..'",
|
||||
"test": "jest"
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
|
|
185
js-packages/webpack-config/src/autoExportLoader.cjs
Normal file
185
js-packages/webpack-config/src/autoExportLoader.cjs
Normal file
|
@ -0,0 +1,185 @@
|
|||
/**
|
||||
* Auto Export Loader
|
||||
*
|
||||
* This loader will automatically pick up all core and extension exports and add them to the registry.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { validate } = require('schema-utils');
|
||||
const { getOptions, interpolateName } = require('loader-utils');
|
||||
|
||||
const optionsSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
extension: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let namespace;
|
||||
|
||||
function addAutoExports(source, pathToModule, moduleName) {
|
||||
let addition = '';
|
||||
|
||||
const defaultExportMatches = [...source.matchAll(/export\s+?default\s(?:abstract\s)?(?:(?:function|abstract|class)\s)?([A-Za-z_]*)/gm)];
|
||||
const defaultExport = defaultExportMatches.length ? defaultExportMatches[0][1] : null;
|
||||
|
||||
// In case of an index.js file that exports multiple modules
|
||||
// we need to add the directory as a module.
|
||||
// For an example checkout the `common/extenders/index.js` file.
|
||||
if (moduleName === 'index') {
|
||||
const id = pathToModule.substring(0, pathToModule.length - 1);
|
||||
|
||||
// Add code at the end of the file to add the file to registry
|
||||
addition += `\nflarum.reg.add('${namespace}', '${id}', ${defaultExport})`;
|
||||
}
|
||||
|
||||
// In a normal case, we do one of two things:
|
||||
else {
|
||||
// 1. If there is a default export, we add the module to the registry with the default export.
|
||||
// Example: `export default class Foo {}` will be added to the registry as `Foo`,
|
||||
// and can be imported using `import Foo from 'flarum/../Foo'`.
|
||||
if (defaultExport) {
|
||||
// Add code at the end of the file to add the file to registry
|
||||
addition += `\nflarum.reg.add('${namespace}', '${pathToModule}${moduleName}', ${defaultExport})`;
|
||||
}
|
||||
|
||||
// 2. If there is no default export, then there are named exports,
|
||||
// so we add the module to the registry with the map of named exports.
|
||||
// Example: `export class Foo {}` will be added to the registry as `{ Foo: 'Foo' }`,
|
||||
// and can be imported using `import { Foo } from 'flarum/../Foo'`,
|
||||
// (checkout the `common/utils/string.ts` file for an example).
|
||||
else {
|
||||
// Another two case scenarios is when using `export { A, B } from 'x'`.
|
||||
// 2.1. If there is a default export, we add the module to the registry with the default export and ignore the named exports.
|
||||
// Example: `export { nanoid as default, x } from 'nanoid'` will be added to the registry as `nanoid`,
|
||||
// and can be imported using `import nanoid from 'flarum/../nanoid'`. x will be ignored.
|
||||
const objectExportWithDefaultMatches = [...source.matchAll(/export\s+?{.*as\s+?default.*}\s+?from\s+?['"](.*)['"]/gm)];
|
||||
|
||||
if (objectExportWithDefaultMatches.length) {
|
||||
let objectDefaultExport = null;
|
||||
|
||||
source = source.replace(/export\s+?{\s?([A-z_0-9]*)\s?as\s+?default.*}\s+?from\s+?['"](.*)['"]/gm, (match, defaultExport, path) => {
|
||||
objectDefaultExport = defaultExport;
|
||||
|
||||
return `import { ${defaultExport} } from '${path}';\nexport default ${defaultExport}`;
|
||||
});
|
||||
|
||||
addition += `\nflarum.reg.add('${namespace}', '${pathToModule}${moduleName}', ${objectDefaultExport})`;
|
||||
}
|
||||
// 2.2. If there is no default export, check for direct exports from other modules.
|
||||
// We add the module to the registry with the map of named exports.
|
||||
// Example: `export { A, B } from 'nanoid'` will be added to the registry as `{ A, B }`,
|
||||
// and can be imported using `import { A, B } from 'flarum/../nanoid'`.
|
||||
else {
|
||||
const exportCurlyPattern = /export\s+?{(.*)}\s+?from\s+?['"](.*)['"]/gm;
|
||||
const namedExportMatches = [...source.matchAll(exportCurlyPattern)];
|
||||
|
||||
if (namedExportMatches.length) {
|
||||
source = source.replaceAll(exportCurlyPattern, (match, names, path) => {
|
||||
return names
|
||||
.split(',')
|
||||
.map((name) => `import { ${name} } from '${path}';\nexport { ${name} }`)
|
||||
.join('\n');
|
||||
});
|
||||
|
||||
// Addition to the registry is taken care of in step 2.3
|
||||
}
|
||||
}
|
||||
|
||||
// 2.3. Finally, we check for all named exports
|
||||
// these can be `export function|class|.. Name ..`
|
||||
// or `export { ... };
|
||||
{
|
||||
const matches = [...source.matchAll(/export\s+?(?:\* as|function|{\s*([A-z0-9, ]+)+\s?}|const|abstract\s?|class)+?\s?([A-Za-z_]*)?/gm)];
|
||||
|
||||
if (matches.length) {
|
||||
const map = matches.reduce((map, match) => {
|
||||
const names = match[1] ? match[1].split(',') : (match[2] ? [match[2]] : null);
|
||||
|
||||
if (!names) {
|
||||
return map;
|
||||
}
|
||||
|
||||
for (let name of names) {
|
||||
name = name.trim();
|
||||
|
||||
if (name === 'interface' || name === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
map += `${name}: ${name},`;
|
||||
}
|
||||
|
||||
return map;
|
||||
}, '');
|
||||
|
||||
// Add code at the end of the file to add the file to registry
|
||||
if (map) addition += `\nflarum.reg.add('${namespace}', '${pathToModule}${moduleName}', { ${map} })`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return source + addition;
|
||||
}
|
||||
|
||||
// Custom loader logic
|
||||
module.exports = function autoExportLoader(source) {
|
||||
const options = getOptions(this) || {};
|
||||
|
||||
validate(optionsSchema, options, {
|
||||
name: 'Flarum Webpack Loader',
|
||||
composerPath: 'Path to the extension composer.json file',
|
||||
});
|
||||
|
||||
// Ensure that composer.json is watched for changes
|
||||
// so that the loader is run again when composer.json
|
||||
// is updated.
|
||||
const composerJsonPath = path.resolve(options.composerPath || '../composer.json');
|
||||
this.addDependency(composerJsonPath);
|
||||
|
||||
// Get the namespace of the module to be exported
|
||||
// the namespace is essentially just the usual extension ID.
|
||||
if (!namespace) {
|
||||
const composerJson = JSON.parse(fs.readFileSync(composerJsonPath, 'utf8'));
|
||||
|
||||
// Get the value of the 'name' property
|
||||
namespace =
|
||||
composerJson.name === 'flarum/core' ? 'core' : composerJson.name.replace('/flarum-ext-', '-').replace('/flarum-', '').replace('/', '-');
|
||||
}
|
||||
|
||||
// Get the type of the module to be exported
|
||||
const location = interpolateName(this, '[folder]/', {
|
||||
context: this.rootContext || this.context,
|
||||
});
|
||||
|
||||
// Get the name of module to be exported
|
||||
const moduleName = interpolateName(this, '[name]', {
|
||||
context: this.rootContext || this.context,
|
||||
});
|
||||
|
||||
// Don't export low level files
|
||||
if ((/(admin|forum)\/$/.test(location) && moduleName !== 'app') || /(compat|ExportRegistry|registry)$/.test(moduleName)) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// Don't export index.js of common
|
||||
if (moduleName === 'index' && location === 'common/') {
|
||||
return source;
|
||||
}
|
||||
|
||||
// Don't export extend.js of extensions
|
||||
if (namespace !== 'core' && /extend$/.test(moduleName)) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// Get the path of the module to be exported
|
||||
// relative to the src directory.
|
||||
// Example: src/forum/components/UserCard.js => forum/components
|
||||
const pathToModule = this.resourcePath.replace(path.resolve(this.rootContext, 'src') + '/', '').replace(/[A-Za-z_]+\.[A-Za-z_]+$/, '');
|
||||
|
||||
return addAutoExports(source, pathToModule, moduleName);
|
||||
};
|
|
@ -55,7 +55,7 @@ if (useBundleAnalyzer) {
|
|||
plugins.push(new (require('webpack-bundle-analyzer').BundleAnalyzerPlugin)());
|
||||
}
|
||||
|
||||
module.exports = function (options = {}) {
|
||||
module.exports = function () {
|
||||
return {
|
||||
// Set up entry points for each of the forum + admin apps, but only
|
||||
// if they exist.
|
||||
|
@ -69,12 +69,15 @@ module.exports = function (options = {}) {
|
|||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
include: /src/, // Only apply this loader to files in the src directory
|
||||
loader: path.resolve(__dirname, './autoExportLoader.cjs'),
|
||||
},
|
||||
{
|
||||
// Matches .js, .jsx, .ts, .tsx
|
||||
// See: https://regexr.com/5snjd
|
||||
test: /\.[jt]sx?$/,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: require('./babel.config'),
|
||||
options: require('../babel.config.cjs'),
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
|
@ -91,33 +94,24 @@ module.exports = function (options = {}) {
|
|||
|
||||
externals: [
|
||||
{
|
||||
'@flarum/core/forum': 'flarum.core',
|
||||
'@flarum/core/admin': 'flarum.core',
|
||||
jquery: 'jQuery',
|
||||
},
|
||||
|
||||
(function () {
|
||||
const externals = {};
|
||||
|
||||
if (options.useExtensions) {
|
||||
for (const extension of options.useExtensions) {
|
||||
externals['@' + extension] =
|
||||
externals['@' + extension + '/forum'] =
|
||||
externals['@' + extension + '/admin'] =
|
||||
"flarum.extensions['" + extension + "']";
|
||||
}
|
||||
}
|
||||
|
||||
return externals;
|
||||
})(),
|
||||
|
||||
// Support importing old-style core modules.
|
||||
function ({ request }, callback) {
|
||||
let namespace;
|
||||
let id;
|
||||
let matches;
|
||||
if ((matches = /^flarum\/(.+)$/.exec(request))) {
|
||||
return callback(null, "root flarum.core.compat['" + matches[1] + "']");
|
||||
namespace = 'core';
|
||||
id = matches[1];
|
||||
} else if ((matches = /^ext:([^\/]+)\/(?:flarum-(?:ext-)?)?([^\/]+)(?:\/(.+))?$/.exec(request))) {
|
||||
namespace = `${matches[1]}-${matches[2]}`;
|
||||
id = matches[3];
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
callback();
|
||||
|
||||
return callback(null, `root flarum.reg.get('${namespace}', '${id}')`);
|
||||
},
|
||||
],
|
||||
|
54
js-packages/webpack-config/tests/autoExportLoader.test.js
Normal file
54
js-packages/webpack-config/tests/autoExportLoader.test.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* @jest-environment node
|
||||
*/
|
||||
import compiler from './compiler.js';
|
||||
import 'regenerator-runtime/runtime';
|
||||
|
||||
const compile = async (path, useFinalOutput = false) => {
|
||||
const stats = await compiler(path);
|
||||
return useFinalOutput
|
||||
? stats.finalOutput
|
||||
: stats.toJson({
|
||||
source: true,
|
||||
}).modules[0].source;
|
||||
};
|
||||
|
||||
test('A directory with index.js that exports multiple modules adds the directory as a module', async () => {
|
||||
let output = await compile('src/common/bars/index.js', true);
|
||||
expect(output).toContain("flarum.reg.add('flarum-framework', 'common/bars', bars)");
|
||||
|
||||
output = await compile('src/common/bars/Acme.js');
|
||||
expect(output).toContain("flarum.reg.add('flarum-framework', 'common/bars/Acme', Acme)");
|
||||
|
||||
output = await compile('src/common/bars/Foo.js');
|
||||
expect(output).toContain("flarum.reg.add('flarum-framework', 'common/bars/Foo', Foo)");
|
||||
});
|
||||
|
||||
test('Simple default exports are added', async () => {
|
||||
const output = await compile('src/common/Test.js');
|
||||
expect(output).toContain("flarum.reg.add('flarum-framework', 'common/Test', Test)");
|
||||
});
|
||||
|
||||
test('Named exports are added', async () => {
|
||||
const output = await compile('src/common/foos/namedExports.js');
|
||||
expect(output).toContain(
|
||||
"flarum.reg.add('flarum-framework', 'common/foos/namedExports', { baz: baz,foo: foo,Bar: Bar,sasha: sasha,flarum: flarum,david: david, })"
|
||||
);
|
||||
});
|
||||
|
||||
test('Export as default from another module is added', async () => {
|
||||
const output = await compile('src/common/foos/exportDefaultFrom.js', true);
|
||||
expect(output).toContain("flarum.reg.add('flarum-framework', 'common/foos/exportDefaultFrom', potato");
|
||||
});
|
||||
|
||||
test('Export from other modules is added', async () => {
|
||||
const output = await compile('src/common/foos/exportFrom.js', true);
|
||||
expect(output).toContain("flarum.reg.add('flarum-framework', 'common/foos/exportFrom', { potato: potato,franz: franz, }");
|
||||
});
|
||||
|
||||
test('Export from with other named exports works', async () => {
|
||||
const output = await compile('src/common/foos/exportFromWithNamedExports.js', true);
|
||||
expect(output).toContain(
|
||||
"flarum.reg.add('flarum-framework', 'common/foos/exportFromWithNamedExports', { potato: potato,franz: franz,baz: baz,foo: foo,Bar: Bar,sasha: sasha,forum: forum,david: david, }"
|
||||
);
|
||||
});
|
48
js-packages/webpack-config/tests/compiler.js
Normal file
48
js-packages/webpack-config/tests/compiler.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import path from 'path';
|
||||
import webpack from 'webpack';
|
||||
import { createFsFromVolume, Volume } from 'memfs';
|
||||
import * as fs from 'fs';
|
||||
|
||||
export default (fixture, options = {}) => {
|
||||
const compiler = webpack({
|
||||
context: __dirname,
|
||||
entry: `./${fixture}`,
|
||||
output: {
|
||||
path: path.resolve(__dirname),
|
||||
filename: 'bundle.js',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: {
|
||||
loader: path.resolve(__dirname, '../src/autoExportLoader.cjs'),
|
||||
options: {
|
||||
...options,
|
||||
composerPath: '../../composer.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
minimizer: [],
|
||||
},
|
||||
});
|
||||
|
||||
compiler.outputFileSystem = createFsFromVolume(new Volume());
|
||||
compiler.outputFileSystem.join = path.join.bind(path);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
compiler.run((err, stats) => {
|
||||
if (err) reject(err);
|
||||
if (stats.hasErrors()) reject(stats.toJson().errors);
|
||||
|
||||
const outputFilepath = path.join(compiler.options.output.path, compiler.options.output.filename);
|
||||
stats.finalOutput = compiler.outputFileSystem.readFileSync(outputFilepath, 'utf-8');
|
||||
|
||||
resolve(stats);
|
||||
});
|
||||
});
|
||||
};
|
1
js-packages/webpack-config/tests/src/common/Test.js
Normal file
1
js-packages/webpack-config/tests/src/common/Test.js
Normal file
|
@ -0,0 +1 @@
|
|||
export default class Test {}
|
1
js-packages/webpack-config/tests/src/common/bars/Acme.js
Normal file
1
js-packages/webpack-config/tests/src/common/bars/Acme.js
Normal file
|
@ -0,0 +1 @@
|
|||
export default class Acme {}
|
1
js-packages/webpack-config/tests/src/common/bars/Foo.js
Normal file
1
js-packages/webpack-config/tests/src/common/bars/Foo.js
Normal file
|
@ -0,0 +1 @@
|
|||
export default class Foo {}
|
|
@ -0,0 +1,9 @@
|
|||
import Acme from './Acme.js';
|
||||
import Foo from './Foo.js';
|
||||
|
||||
const bars = {
|
||||
Acme,
|
||||
Foo,
|
||||
};
|
||||
|
||||
export default bars;
|
|
@ -0,0 +1 @@
|
|||
export { potato as default } from '../support/potato.js';
|
|
@ -0,0 +1 @@
|
|||
export { potato, franz } from '../support/potato.js';
|
|
@ -0,0 +1,16 @@
|
|||
export { potato, franz } from '../support/potato.js';
|
||||
|
||||
export function baz() {}
|
||||
|
||||
export function foo() {}
|
||||
|
||||
export class Bar {}
|
||||
|
||||
const sasha = 'camel';
|
||||
|
||||
export { sasha };
|
||||
|
||||
const forum = 'Flarum';
|
||||
const david = 'david';
|
||||
|
||||
export { forum, david };
|
|
@ -0,0 +1,14 @@
|
|||
export function baz() {}
|
||||
|
||||
export function foo() {}
|
||||
|
||||
export class Bar {}
|
||||
|
||||
const sasha = 'camel';
|
||||
|
||||
export { sasha };
|
||||
|
||||
const flarum = 'Flarum';
|
||||
const david = 'david';
|
||||
|
||||
export { flarum, david };
|
|
@ -0,0 +1,4 @@
|
|||
const potato = 'potato';
|
||||
const franz = 'franz';
|
||||
|
||||
export { potato, franz };
|
Loading…
Reference in New Issue
Block a user