From 141a2eba565a6fd8b6d8be200481344550501974 Mon Sep 17 00:00:00 2001 From: Vladislav Shkodin Date: Mon, 8 Feb 2021 20:01:21 +0200 Subject: [PATCH] refactor: convert function expressions to declarations (#4926) --- .eslintrc.js | 1 + babel.config.js | 8 +- packages/netlify-cms-backend-azure/src/API.ts | 4 +- .../src/implementation.ts | 4 +- .../netlify-cms-backend-bitbucket/src/API.ts | 8 +- .../src/implementation.ts | 4 +- .../src/netlify-lfs-client.ts | 59 ++- .../netlify-cms-backend-github/src/API.ts | 19 +- .../src/GraphQLAPI.ts | 4 +- .../src/__tests__/API.spec.js | 4 +- .../netlify-cms-backend-github/src/queries.ts | 28 +- .../netlify-cms-backend-gitlab/src/API.ts | 4 +- .../src/__tests__/gitlab.spec.js | 10 +- .../src/implementation.ts | 9 +- .../src/implementation.ts | 12 +- .../src/actions/__tests__/config.spec.js | 4 +- .../netlify-cms-core/src/actions/config.js | 48 +- .../netlify-cms-core/src/actions/entries.ts | 50 +- .../netlify-cms-core/src/actions/media.ts | 4 +- .../src/actions/mediaLibrary.ts | 5 +- .../netlify-cms-core/src/actions/waitUntil.ts | 10 +- packages/netlify-cms-core/src/backend.ts | 54 +- packages/netlify-cms-core/src/bootstrap.js | 26 +- .../src/components/App/App.js | 8 +- .../src/components/App/Header.js | 30 +- .../src/components/App/NotFoundPage.js | 12 +- .../src/components/Collection/Collection.js | 4 +- .../Collection/CollectionControls.js | 6 +- .../components/Collection/CollectionTop.js | 8 +- .../components/Collection/ControlButton.js | 4 +- .../components/Collection/Entries/Entries.js | 6 +- .../Collection/Entries/EntriesCollection.js | 16 +- .../Collection/Entries/EntryCard.js | 18 +- .../__tests__/EntriesCollection.spec.js | 11 +- .../components/Collection/FilterControl.js | 4 +- .../src/components/Collection/GroupControl.js | 4 +- .../components/Collection/NestedCollection.js | 32 +- .../src/components/Collection/SortControl.js | 4 +- .../components/Collection/ViewStyleControl.js | 4 +- .../Collection/__tests__/Collection.spec.js | 5 +- .../__tests__/NestedCollection.spec.js | 5 +- .../Editor/EditorControlPane/EditorControl.js | 20 +- .../EditorControlPane/EditorControlPane.js | 8 +- .../Editor/EditorControlPane/Widget.js | 19 +- .../src/components/Editor/EditorInterface.js | 56 ++- .../EditorPreviewPane/EditorPreviewPane.js | 12 +- .../EditorWidgets/Unknown/UnknownControl.js | 4 +- .../EditorWidgets/Unknown/UnknownPreview.js | 4 +- .../components/MediaLibrary/EmptyMessage.js | 12 +- .../components/MediaLibrary/MediaLibrary.js | 4 +- .../MediaLibrary/MediaLibraryCardGrid.js | 18 +- .../MediaLibrary/MediaLibraryHeader.js | 18 +- .../MediaLibrary/MediaLibraryModal.js | 6 +- .../MediaLibrary/MediaLibrarySearch.js | 26 +- .../MediaLibrary/MediaLibraryTop.js | 6 +- .../src/components/UI/DragDrop.js | 14 +- .../src/components/UI/ErrorBoundary.js | 17 +- .../src/components/UI/FileUploadButton.js | 24 +- .../src/components/UI/Modal.js | 20 +- .../src/components/UI/SettingsDropdown.js | 69 +-- .../src/components/UI/Toast.js | 38 +- .../UI/__tests__/ErrorBoundary.spec.js | 4 +- .../src/components/Workflow/WorkflowCard.js | 54 +- .../src/components/Workflow/WorkflowList.js | 4 +- .../src/constants/configSchema.js | 368 +++++++------- .../netlify-cms-core/src/formats/formats.js | 7 +- .../src/formats/frontmatter.js | 22 +- .../netlify-cms-core/src/formats/helpers.js | 18 +- packages/netlify-cms-core/src/formats/toml.js | 4 +- packages/netlify-cms-core/src/formats/yaml.js | 4 +- .../netlify-cms-core/src/lib/formatters.ts | 49 +- packages/netlify-cms-core/src/lib/i18n.ts | 116 ++--- .../src/lib/serializeEntryValues.js | 12 +- .../netlify-cms-core/src/lib/urlHelper.ts | 10 +- packages/netlify-cms-core/src/mediaLibrary.ts | 9 +- .../reducers/__tests__/collections.spec.js | 4 +- .../src/reducers/collections.ts | 134 ++--- .../src/reducers/combinedReducer.js | 4 +- .../netlify-cms-core/src/reducers/config.ts | 13 +- .../netlify-cms-core/src/reducers/cursors.js | 9 +- .../netlify-cms-core/src/reducers/deploys.js | 9 +- .../src/reducers/editorialWorkflow.ts | 20 +- .../netlify-cms-core/src/reducers/entries.ts | 132 ++--- .../src/reducers/entryDraft.js | 8 +- .../netlify-cms-core/src/reducers/globalUI.js | 12 +- .../netlify-cms-core/src/reducers/index.ts | 44 +- .../src/reducers/integrations.ts | 13 +- .../src/reducers/mediaLibrary.ts | 4 +- .../netlify-cms-core/src/reducers/medias.ts | 5 +- .../netlify-cms-core/src/reducers/search.js | 4 +- .../src/redux/middleware/waitUntilAction.ts | 3 +- .../netlify-cms-core/src/routing/history.ts | 17 +- .../src/valueObjects/EditorComponent.js | 5 +- packages/netlify-cms-core/webpack.config.js | 4 +- .../src/__tests__/index.spec.js | 5 +- packages/netlify-cms-lib-util/src/API.ts | 42 +- packages/netlify-cms-lib-util/src/APIUtils.ts | 39 +- packages/netlify-cms-lib-util/src/Cursor.ts | 23 +- .../src/__tests__/backendUtil.spec.js | 9 +- .../netlify-cms-lib-util/src/asyncLock.ts | 12 +- .../netlify-cms-lib-util/src/backendUtil.ts | 50 +- packages/netlify-cms-lib-util/src/git-lfs.ts | 27 +- .../src/implementation.ts | 82 ++- packages/netlify-cms-lib-util/src/path.ts | 5 +- packages/netlify-cms-lib-util/src/promise.ts | 17 +- .../netlify-cms-lib-util/src/unsentRequest.js | 73 +-- .../src/stringTemplate.ts | 18 +- .../src/validations.ts | 26 +- .../src/index.js | 4 +- .../src/index.js | 10 +- .../netlify-cms-proxy-server/src/logger.ts | 4 +- .../src/middlewares.ts | 12 +- .../src/middlewares/common/index.ts | 4 +- .../src/middlewares/joi/customValidators.ts | 5 +- .../src/middlewares/joi/index.spec.ts | 4 +- .../src/middlewares/joi/index.ts | 30 +- .../src/middlewares/localFs/index.spec.ts | 4 +- .../src/middlewares/localFs/index.ts | 12 +- .../src/middlewares/localGit/index.spec.ts | 7 +- .../src/middlewares/localGit/index.ts | 54 +- .../src/middlewares/utils/entries.ts | 18 +- .../src/middlewares/utils/fs.ts | 30 +- .../src/AuthenticationPage.js | 14 +- .../netlify-cms-ui-default/src/Dropdown.js | 98 ++-- .../netlify-cms-ui-default/src/FieldLabel.js | 4 +- packages/netlify-cms-ui-default/src/Icon.js | 8 +- .../netlify-cms-ui-default/src/IconButton.js | 24 +- .../src/ListItemTopBar.js | 36 +- packages/netlify-cms-ui-default/src/Toggle.js | 44 +- packages/netlify-cms-ui-default/src/styles.js | 148 +++--- .../src/BooleanControl.js | 18 +- .../netlify-cms-widget-boolean/src/index.js | 12 +- .../src/CodePreview.js | 20 +- .../src/SettingsButton.js | 12 +- .../src/SettingsPane.js | 104 ++-- packages/netlify-cms-widget-code/src/index.js | 20 +- .../src/ColorControl.js | 18 +- .../src/ColorPreview.js | 4 +- .../src/index.js | 14 +- .../src/DatePreview.js | 6 +- packages/netlify-cms-widget-date/src/index.js | 14 +- .../src/DateTimeControl.js | 4 +- .../src/DateTimePreview.js | 6 +- .../netlify-cms-widget-datetime/src/index.js | 16 +- .../src/FilePreview.js | 10 +- packages/netlify-cms-widget-file/src/index.js | 17 +- .../src/withFileControl.js | 4 +- .../src/ImagePreview.js | 12 +- .../netlify-cms-widget-image/src/index.js | 17 +- .../src/ListControl.js | 4 +- .../src/__tests__/ListControl.spec.js | 16 +- packages/netlify-cms-widget-list/src/index.js | 17 +- .../netlify-cms-widget-map/src/MapPreview.js | 6 +- packages/netlify-cms-widget-map/src/index.js | 17 +- .../src/withMapControl.js | 10 +- .../src/MarkdownControl/RawEditor.js | 4 +- .../src/MarkdownControl/Toolbar.js | 6 +- .../src/MarkdownControl/ToolbarButton.js | 22 +- .../src/MarkdownControl/VisualEditor.js | 16 +- .../MarkdownControl/__tests__/slate.spec.js | 6 +- .../MarkdownControl/components/Shortcode.js | 8 +- .../MarkdownControl/components/VoidBlock.js | 34 +- .../src/MarkdownControl/index.js | 10 +- .../plugins/BreakToDefaultBlock.js | 34 +- .../src/MarkdownControl/plugins/CloseBlock.js | 38 +- .../plugins/CommandsAndQueries.js | 226 ++++----- .../plugins/CopyPasteVisual.js | 8 +- .../MarkdownControl/plugins/ForceInsert.js | 78 +-- .../src/MarkdownControl/plugins/Hotkey.js | 4 +- .../src/MarkdownControl/plugins/LineBreak.js | 26 +- .../src/MarkdownControl/plugins/Link.js | 46 +- .../src/MarkdownControl/plugins/List.js | 4 +- .../src/MarkdownControl/plugins/QuoteBlock.js | 170 +++---- .../src/MarkdownControl/plugins/SelectAll.js | 22 +- .../src/MarkdownControl/plugins/Shortcode.js | 32 +- .../src/MarkdownControl/plugins/visual.js | 72 +-- .../src/MarkdownControl/renderers.js | 318 +++++++----- .../src/MarkdownControl/schema.js | 466 +++++++++--------- .../netlify-cms-widget-markdown/src/index.js | 16 +- .../serializers/__tests__/commonmark.spec.js | 6 +- .../__tests__/remarkAllowHtmlEntities.spec.js | 4 +- .../remarkEscapeMarkdownEntities.spec.js | 4 +- .../__tests__/remarkPaddedLinks.spec.js | 10 +- .../__tests__/remarkShortcodes.spec.js | 5 +- .../remarkStripTrailingBreaks.spec.js | 4 +- .../src/serializers/index.js | 24 +- .../src/serializers/rehypePaperEmoji.js | 5 +- .../remarkEscapeMarkdownEntities.js | 4 +- .../src/serializers/remarkSlate.js | 22 +- .../serializers/remarkStripTrailingBreaks.js | 5 +- .../src/serializers/slateRemark.js | 6 +- .../src/NumberPreview.js | 4 +- .../netlify-cms-widget-number/src/index.js | 16 +- .../src/ObjectPreview.js | 12 +- .../netlify-cms-widget-object/src/index.js | 16 +- .../src/RelationControl.js | 8 +- .../src/RelationPreview.js | 4 +- .../src/__tests__/relation.spec.js | 9 +- .../netlify-cms-widget-relation/src/index.js | 16 +- .../src/SelectPreview.js | 30 +- .../netlify-cms-widget-select/src/index.js | 16 +- .../src/StringPreview.js | 4 +- .../netlify-cms-widget-string/src/index.js | 14 +- .../src/TextPreview.js | 4 +- packages/netlify-cms-widget-text/src/index.js | 14 +- scripts/externals.js | 5 +- scripts/webpack.js | 136 ++--- website/gatsby-node.js | 4 +- website/src/cms/cms.js | 100 ++-- website/src/components/chat-button.js | 12 +- .../src/components/community-channels-list.js | 26 +- website/src/components/community.js | 74 +-- website/src/components/docs-nav.js | 8 +- website/src/components/docsearch.js | 4 +- website/src/components/edit-link.js | 70 +-- website/src/components/event-box.js | 4 +- website/src/components/features.js | 29 +- website/src/components/footer.js | 66 +-- website/src/components/header.js | 16 +- website/src/components/home-section.js | 24 +- website/src/components/layout.js | 18 +- website/src/components/markdown.js | 4 +- website/src/components/markdownify.js | 6 +- website/src/components/notification.js | 12 +- website/src/components/notifications.js | 4 +- website/src/components/page-hero.js | 38 +- website/src/components/release.js | 4 +- website/src/components/sidebar-layout.js | 30 +- website/src/components/table-of-contents.js | 4 +- website/src/components/twitter-meta.js | 22 +- website/src/components/video-embed.js | 28 +- website/src/components/whats-new.js | 36 +- website/src/components/widget-doc.js | 4 +- website/src/components/widgets.js | 8 +- website/src/global-styles.js | 4 +- website/src/pages/blog.js | 64 +-- website/src/pages/community.js | 4 +- website/src/pages/index.js | 4 +- website/src/templates/blog-post.js | 40 +- website/src/templates/doc-page.js | 49 +- website/src/utils.js | 4 +- 241 files changed, 3444 insertions(+), 2933 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index ffdec6de..dc511f58 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,6 +30,7 @@ module.exports = { '@emotion/styled-import': 'error', 'require-atomic-updates': [0], 'object-shorthand': ['error', 'always'], + 'func-style': ['error', 'declaration'], 'prefer-const': [ 'error', { diff --git a/babel.config.js b/babel.config.js index a181a895..953109f2 100644 --- a/babel.config.js +++ b/babel.config.js @@ -74,7 +74,7 @@ const defaultPlugins = [ ], ]; -const presets = () => { +function presets() { return [ '@babel/preset-react', '@babel/preset-env', @@ -86,9 +86,9 @@ const presets = () => { ], '@babel/typescript', ]; -}; +} -const plugins = () => { +function plugins() { if (isESM) { return [ ...defaultPlugins, @@ -129,7 +129,7 @@ const plugins = () => { } return defaultPlugins; -}; +} module.exports = { presets: presets(), diff --git a/packages/netlify-cms-backend-azure/src/API.ts b/packages/netlify-cms-backend-azure/src/API.ts index abc2e4f3..ae8ff766 100644 --- a/packages/netlify-cms-backend-azure/src/API.ts +++ b/packages/netlify-cms-backend-azure/src/API.ts @@ -161,7 +161,7 @@ function delay(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } -const getChangeItem = (item: AzureCommitItem) => { +function getChangeItem(item: AzureCommitItem) { switch (item.action) { case AzureCommitChangeType.ADD: return { @@ -195,7 +195,7 @@ const getChangeItem = (item: AzureCommitItem) => { default: return {}; } -}; +} type AzureCommitItem = { action: AzureCommitChangeType; diff --git a/packages/netlify-cms-backend-azure/src/implementation.ts b/packages/netlify-cms-backend-azure/src/implementation.ts index b7c2792c..d303b471 100644 --- a/packages/netlify-cms-backend-azure/src/implementation.ts +++ b/packages/netlify-cms-backend-azure/src/implementation.ts @@ -33,7 +33,7 @@ import { const MAX_CONCURRENT_DOWNLOADS = 10; -const parseAzureRepo = (config: Config) => { +function parseAzureRepo(config: Config) { const { repo } = config.backend; if (typeof repo !== 'string') { @@ -51,7 +51,7 @@ const parseAzureRepo = (config: Config) => { project, repoName, }; -}; +} export default class Azure implements Implementation { lock: AsyncLock; diff --git a/packages/netlify-cms-backend-bitbucket/src/API.ts b/packages/netlify-cms-backend-bitbucket/src/API.ts index 0dc2e8c4..05d2d134 100644 --- a/packages/netlify-cms-backend-bitbucket/src/API.ts +++ b/packages/netlify-cms-backend-bitbucket/src/API.ts @@ -186,14 +186,14 @@ export const API_NAME = 'Bitbucket'; const APPLICATION_JSON = 'application/json; charset=utf-8'; -const replace404WithEmptyResponse = (err: FetchError) => { +function replace404WithEmptyResponse(err: FetchError) { if (err && err.status === 404) { console.log('This 404 was expected and handled appropriately.'); return { size: 0, values: [] as BitBucketFile[] } as BitBucketSrcResult; } else { return Promise.reject(err); } -}; +} export default class API { apiRoot: string; @@ -653,8 +653,8 @@ export default class API { params: { pagelen: 50, q: oneLine` - source.repository.full_name = "${this.repo}" - AND state = "${BitBucketPullRequestState.OPEN}" + source.repository.full_name = "${this.repo}" + AND state = "${BitBucketPullRequestState.OPEN}" AND destination.branch.name = "${this.branch}" AND comment_count > 0 AND ${sourceQuery} diff --git a/packages/netlify-cms-backend-git-gateway/src/implementation.ts b/packages/netlify-cms-backend-git-gateway/src/implementation.ts index f7b026e3..e3108292 100644 --- a/packages/netlify-cms-backend-git-gateway/src/implementation.ts +++ b/packages/netlify-cms-backend-git-gateway/src/implementation.ts @@ -121,11 +121,11 @@ interface NetlifyUser extends Credentials { user_metadata: { full_name: string; avatar_url: string }; } -const apiGet = async (path: string) => { +async function apiGet(path: string) { const apiRoot = 'https://api.netlify.com/api/v1/sites'; const response = await fetch(`${apiRoot}/${path}`).then(res => res.json()); return response; -}; +} export default class GitGateway implements Implementation { config: Config; diff --git a/packages/netlify-cms-backend-git-gateway/src/netlify-lfs-client.ts b/packages/netlify-cms-backend-git-gateway/src/netlify-lfs-client.ts index d8f004db..afad0ad3 100644 --- a/packages/netlify-cms-backend-git-gateway/src/netlify-lfs-client.ts +++ b/packages/netlify-cms-backend-git-gateway/src/netlify-lfs-client.ts @@ -15,8 +15,9 @@ type ClientConfig = { transformImages: ImageTransformations | boolean; }; -export const matchPath = ({ patterns }: ClientConfig, path: string) => - patterns.some(pattern => minimatch(path, pattern, { matchBase: true })); +export function matchPath({ patterns }: ClientConfig, path: string) { + return patterns.some(pattern => minimatch(path, pattern, { matchBase: true })); +} // // API interactions @@ -26,10 +27,10 @@ const defaultContentHeaders = { ['Content-Type']: 'application/vnd.git-lfs+json', }; -const resourceExists = async ( +async function resourceExists( { rootURL, makeAuthorizedRequest }: ClientConfig, { sha, size }: PointerFile, -) => { +) { const response = await makeAuthorizedRequest({ url: `${rootURL}/verify`, method: 'POST', @@ -45,20 +46,20 @@ const resourceExists = async ( // TODO: what kind of error to throw here? APIError doesn't seem // to fit -}; +} -const getTransofrmationsParams = (t: boolean | ImageTransformations) => { +function getTransofrmationsParams(t: boolean | ImageTransformations) { if (isPlainObject(t) && !isEmpty(t)) { const { nf_resize: resize, w, h } = t as ImageTransformations; return `?nf_resize=${resize}&w=${w}&h=${h}`; } return ''; -}; +} -const getDownloadURL = async ( +async function getDownloadURL( { rootURL, transformImages: t, makeAuthorizedRequest }: ClientConfig, { sha }: PointerFile, -) => { +) { try { const transformation = getTransofrmationsParams(t); const transformedPromise = makeAuthorizedRequest(`${rootURL}/origin/${sha}${transformation}`); @@ -81,21 +82,23 @@ const getDownloadURL = async ( console.error(error); return { url: '', blob: new Blob() }; } -}; +} -const uploadOperation = (objects: PointerFile[]) => ({ - operation: 'upload', - transfers: ['basic'], - objects: objects.map(({ sha, ...rest }) => ({ ...rest, oid: sha })), -}); +function uploadOperation(objects: PointerFile[]) { + return { + operation: 'upload', + transfers: ['basic'], + objects: objects.map(({ sha, ...rest }) => ({ ...rest, oid: sha })), + }; +} -const getResourceUploadURLs = async ( +async function getResourceUploadURLs( { rootURL, makeAuthorizedRequest, }: { rootURL: string; makeAuthorizedRequest: MakeAuthorizedRequest }, pointerFiles: PointerFile[], -) => { +) { const response = await makeAuthorizedRequest({ url: `${rootURL}/objects/batch`, method: 'POST', @@ -113,19 +116,20 @@ const getResourceUploadURLs = async ( }, ); return uploadUrls; -}; +} -const uploadBlob = (uploadURL: string, blob: Blob) => - unsentRequest.fetchWithTimeout(uploadURL, { +function uploadBlob(uploadURL: string, blob: Blob) { + return unsentRequest.fetchWithTimeout(uploadURL, { method: 'PUT', body: blob, }); +} -const uploadResource = async ( +async function uploadResource( clientConfig: ClientConfig, { sha, size }: PointerFile, resource: Blob, -) => { +) { const existingFile = await resourceExists(clientConfig, { sha, size }); if (existingFile) { return sha; @@ -133,13 +137,14 @@ const uploadResource = async ( const [uploadURL] = await getResourceUploadURLs(clientConfig, [{ sha, size }]); await uploadBlob(uploadURL, resource); return sha; -}; +} // // Create Large Media client -const configureFn = (config: ClientConfig, fn: Function) => (...args: unknown[]) => - fn(config, ...args); +function configureFn(config: ClientConfig, fn: Function) { + return (...args: unknown[]) => fn(config, ...args); +} const clientFns: Record = { resourceExists, @@ -159,7 +164,7 @@ export type Client = { enabled: boolean; }; -export const getClient = (clientConfig: ClientConfig) => { +export function getClient(clientConfig: ClientConfig) { return flow([ Object.keys, map((key: string) => [key, configureFn(clientConfig, clientFns[key])]), @@ -170,4 +175,4 @@ export const getClient = (clientConfig: ClientConfig) => { enabled: clientConfig.enabled, }), ])(clientFns); -}; +} diff --git a/packages/netlify-cms-backend-github/src/API.ts b/packages/netlify-cms-backend-github/src/API.ts index 30cba911..f23dde14 100644 --- a/packages/netlify-cms-backend-github/src/API.ts +++ b/packages/netlify-cms-backend-github/src/API.ts @@ -129,12 +129,15 @@ type MediaFile = { path: string; }; -const withCmsLabel = (pr: GitHubPull, cmsLabelPrefix: string) => - pr.labels.some(l => isCMSLabel(l.name, cmsLabelPrefix)); -const withoutCmsLabel = (pr: GitHubPull, cmsLabelPrefix: string) => - pr.labels.every(l => !isCMSLabel(l.name, cmsLabelPrefix)); +function withCmsLabel(pr: GitHubPull, cmsLabelPrefix: string) { + return pr.labels.some(l => isCMSLabel(l.name, cmsLabelPrefix)); +} -const getTreeFiles = (files: GitHubCompareFiles) => { +function withoutCmsLabel(pr: GitHubPull, cmsLabelPrefix: string) { + return pr.labels.every(l => !isCMSLabel(l.name, cmsLabelPrefix)); +} + +function getTreeFiles(files: GitHubCompareFiles) { const treeFiles = files.reduce((arr, file) => { if (file.status === 'removed') { // delete the file @@ -152,7 +155,7 @@ const getTreeFiles = (files: GitHubCompareFiles) => { }, [] as { sha: string | null; path: string }[]); return treeFiles; -}; +} export type Diff = { path: string; @@ -446,7 +449,7 @@ export default class API { headers: { Accept: 'application/vnd.github.v3.raw' }, }; - const errorHandler = (err: Error) => { + function errorHandler(err: Error) { if (err.message === 'Not Found') { console.log( '%c %s does not have metadata', @@ -455,7 +458,7 @@ export default class API { ); } throw err; - }; + } if (!this.useOpenAuthoring) { const result = await this.request( diff --git a/packages/netlify-cms-backend-github/src/GraphQLAPI.ts b/packages/netlify-cms-backend-github/src/GraphQLAPI.ts index c14048b9..42be456f 100644 --- a/packages/netlify-cms-backend-github/src/GraphQLAPI.ts +++ b/packages/netlify-cms-backend-github/src/GraphQLAPI.ts @@ -69,14 +69,14 @@ type GraphQLPullRequest = { }; }; -const transformPullRequest = (pr: GraphQLPullRequest) => { +function transformPullRequest(pr: GraphQLPullRequest) { return { ...pr, labels: pr.labels.nodes, head: { ref: pr.headRefName, sha: pr.headRefOid, repo: { fork: pr.repository.isFork } }, base: { ref: pr.baseRefName, sha: pr.baseRefOid }, }; -}; +} type Error = GraphQLError & { type: string }; diff --git a/packages/netlify-cms-backend-github/src/__tests__/API.spec.js b/packages/netlify-cms-backend-github/src/__tests__/API.spec.js index 37da94ff..fc308c20 100644 --- a/packages/netlify-cms-backend-github/src/__tests__/API.spec.js +++ b/packages/netlify-cms-backend-github/src/__tests__/API.spec.js @@ -8,7 +8,7 @@ describe('github API', () => { jest.resetAllMocks(); }); - const mockAPI = (api, responses) => { + function mockAPI(api, responses) { api.request = jest.fn().mockImplementation((path, options = {}) => { const normalizedPath = path.indexOf('?') !== -1 ? path.substr(0, path.indexOf('?')) : path; const response = responses[normalizedPath]; @@ -16,7 +16,7 @@ describe('github API', () => { ? Promise.resolve(response(options)) : Promise.reject(new Error(`No response for path '${normalizedPath}'`)); }); - }; + } describe('editorialWorkflowGit', () => { it('should create PR with correct base branch name when publishing with editorial workflow', () => { diff --git a/packages/netlify-cms-backend-github/src/queries.ts b/packages/netlify-cms-backend-github/src/queries.ts index 4623a25c..8267cb83 100644 --- a/packages/netlify-cms-backend-github/src/queries.ts +++ b/packages/netlify-cms-backend-github/src/queries.ts @@ -62,7 +62,7 @@ export const statues = gql` ${fragments.object} `; -const buildFilesQuery = (depth = 1) => { +function buildFilesQuery(depth = 1) { const PLACE_HOLDER = 'PLACE_HOLDER'; let query = oneLine` ...ObjectParts @@ -93,21 +93,23 @@ const buildFilesQuery = (depth = 1) => { query = query.replace(PLACE_HOLDER, ''); return query; -}; +} -export const files = (depth: number) => gql` - query files($owner: String!, $name: String!, $expression: String!) { - repository(owner: $owner, name: $name) { - ...RepositoryParts - object(expression: $expression) { - ${buildFilesQuery(depth)} +export function files(depth: number) { + return gql` + query files($owner: String!, $name: String!, $expression: String!) { + repository(owner: $owner, name: $name) { + ...RepositoryParts + object(expression: $expression) { + ${buildFilesQuery(depth)} + } } } - } - ${fragments.repository} - ${fragments.object} - ${fragments.fileEntry} -`; + ${fragments.repository} + ${fragments.object} + ${fragments.fileEntry} + `; +} const branchQueryPart = ` branch: ref(qualifiedName: $qualifiedName) { diff --git a/packages/netlify-cms-backend-gitlab/src/API.ts b/packages/netlify-cms-backend-gitlab/src/API.ts index 702aaf20..c33800a5 100644 --- a/packages/netlify-cms-backend-gitlab/src/API.ts +++ b/packages/netlify-cms-backend-gitlab/src/API.ts @@ -171,14 +171,14 @@ type GitLabCommit = { message: string; }; -export const getMaxAccess = (groups: { group_access_level: number }[]) => { +export function getMaxAccess(groups: { group_access_level: number }[]) { return groups.reduce((previous, current) => { if (current.group_access_level > previous.group_access_level) { return current; } return previous; }, groups[0]); -}; +} export default class API { apiRoot: string; diff --git a/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js b/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js index 7af26cfa..4ed90c0a 100644 --- a/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js +++ b/packages/netlify-cms-backend-gitlab/src/__tests__/gitlab.spec.js @@ -8,7 +8,7 @@ import AuthenticationPage from '../AuthenticationPage'; const { Backend, LocalStorageAuthStore } = jest.requireActual('netlify-cms-core/src/backend'); -const generateEntries = (path, length) => { +function generateEntries(path, length) { const entries = Array.from({ length }, (val, idx) => { const count = idx + 1; const id = `00${count}`.slice(-3); @@ -37,7 +37,7 @@ const generateEntries = (path, length) => { {}, ), }; -}; +} const manyEntries = generateEntries('many-entries', 500); @@ -222,8 +222,10 @@ describe('gitlab backend', () => { const pageNum = parseInt(page, 10); const pageCountNum = parseInt(pageCount, 10); const url = `${backend.implementation.apiRoot}${basePath}`; - const link = linkPage => - `<${url}?id=${expectedRepo}&page=${linkPage}&path=${path}&per_page=${perPage}&recursive=false>`; + + function link(linkPage) { + return `<${url}?id=${expectedRepo}&page=${linkPage}&path=${path}&per_page=${perPage}&recursive=false>`; + } const linkHeader = oneLine` ${link(1)}; rel="first", diff --git a/packages/netlify-cms-backend-proxy/src/implementation.ts b/packages/netlify-cms-backend-proxy/src/implementation.ts index c6298fb5..57114387 100644 --- a/packages/netlify-cms-backend-proxy/src/implementation.ts +++ b/packages/netlify-cms-backend-proxy/src/implementation.ts @@ -14,11 +14,10 @@ import { } from 'netlify-cms-lib-util'; import AuthenticationPage from './AuthenticationPage'; -const serializeAsset = async (assetProxy: AssetProxy) => { +async function serializeAsset(assetProxy: AssetProxy) { const base64content = await assetProxy.toBase64!(); - return { path: assetProxy.path, content: base64content, encoding: 'base64' }; -}; +} type MediaFile = { id: string; @@ -28,7 +27,7 @@ type MediaFile = { path: string; }; -const deserializeMediaFile = ({ id, content, encoding, path, name }: MediaFile) => { +function deserializeMediaFile({ id, content, encoding, path, name }: MediaFile) { let byteArray = new Uint8Array(0); if (encoding !== 'base64') { console.error(`Unsupported encoding '${encoding}' for file '${path}'`); @@ -43,7 +42,7 @@ const deserializeMediaFile = ({ id, content, encoding, path, name }: MediaFile) const file = blobToFileObj(name, blob); const url = URL.createObjectURL(file); return { id, name, path, file, size: file.size, url, displayURL: url }; -}; +} export default class ProxyBackend implements Implementation { proxyUrl: string; diff --git a/packages/netlify-cms-backend-test/src/implementation.ts b/packages/netlify-cms-backend-test/src/implementation.ts index f05412dd..371ba267 100644 --- a/packages/netlify-cms-backend-test/src/implementation.ts +++ b/packages/netlify-cms-backend-test/src/implementation.ts @@ -74,13 +74,13 @@ function deleteFile(path: string, tree: RepoTree) { const pageSize = 10; -const getCursor = ( +function getCursor( folder: string, extension: string, entries: ImplementationEntry[], index: number, depth: number, -) => { +) { const count = entries.length; const pageCount = Math.floor(count / pageSize); return Cursor.create({ @@ -91,16 +91,16 @@ const getCursor = ( meta: { index, count, pageSize, pageCount }, data: { folder, extension, index, pageCount, depth }, }); -}; +} -export const getFolderFiles = ( +export function getFolderFiles( tree: RepoTree, folder: string, extension: string, depth: number, files = [] as RepoFile[], path = folder, -) => { +) { if (depth <= 0) { return files; } @@ -118,7 +118,7 @@ export const getFolderFiles = ( }); return files; -}; +} export default class TestBackend implements Implementation { mediaFolder: string; diff --git a/packages/netlify-cms-core/src/actions/__tests__/config.spec.js b/packages/netlify-cms-core/src/actions/__tests__/config.spec.js index 90367b68..b4a98f9d 100644 --- a/packages/netlify-cms-core/src/actions/__tests__/config.spec.js +++ b/packages/netlify-cms-core/src/actions/__tests__/config.spec.js @@ -817,14 +817,14 @@ describe('config', () => { }); describe('detectProxyServer', () => { - const assetFetchCalled = (url = 'http://localhost:8081/api/v1') => { + function assetFetchCalled(url = 'http://localhost:8081/api/v1') { expect(global.fetch).toHaveBeenCalledTimes(1); expect(global.fetch).toHaveBeenCalledWith(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'info' }), }); - }; + } beforeEach(() => { delete window.location; diff --git a/packages/netlify-cms-core/src/actions/config.js b/packages/netlify-cms-core/src/actions/config.js index fda46a24..f38545ab 100644 --- a/packages/netlify-cms-core/src/actions/config.js +++ b/packages/netlify-cms-core/src/actions/config.js @@ -13,7 +13,7 @@ export const CONFIG_REQUEST = 'CONFIG_REQUEST'; export const CONFIG_SUCCESS = 'CONFIG_SUCCESS'; export const CONFIG_FAILURE = 'CONFIG_FAILURE'; -const traverseFieldsJS = (fields, updater) => { +function traverseFieldsJS(fields, updater) { return fields.map(field => { let newField = updater(field); if (newField.fields) { @@ -26,9 +26,9 @@ const traverseFieldsJS = (fields, updater) => { return newField; }); -}; +} -const getConfigUrl = () => { +function getConfigUrl() { const validTypes = { 'text/yaml': 'yaml', 'application/x-yaml': 'yaml' }; const configLinkEl = document.querySelector('link[rel="cms-config-url"]'); const isValidLink = configLinkEl && validTypes[configLinkEl.type] && get(configLinkEl, 'href'); @@ -38,14 +38,14 @@ const getConfigUrl = () => { return link; } return 'config.yml'; -}; +} -const setDefaultPublicFolder = map => { +function setDefaultPublicFolder(map) { if (map.has('media_folder') && !map.has('public_folder')) { map = map.set('public_folder', map.get('media_folder')); } return map; -}; +} // Mapping between existing camelCase and its snake_case counterpart const WIDGET_KEY_MAP = { @@ -60,7 +60,7 @@ const WIDGET_KEY_MAP = { optionsLength: 'options_length', }; -const setSnakeCaseConfig = field => { +function setSnakeCaseConfig(field) { const deprecatedKeys = Object.keys(WIDGET_KEY_MAP).filter(camel => camel in field); const snakeValues = deprecatedKeys.map(camel => { const snake = WIDGET_KEY_MAP[camel]; @@ -71,18 +71,18 @@ const setSnakeCaseConfig = field => { }); return Object.assign({}, field, ...snakeValues); -}; +} -const setI18nField = field => { +function setI18nField(field) { if (field.get(I18N) === true) { field = field.set(I18N, I18N_FIELD.TRANSLATE); } else if (field.get(I18N) === false || !field.has(I18N)) { field = field.set(I18N, I18N_FIELD.NONE); } return field; -}; +} -const setI18nDefaults = (defaultI18n, collectionOrFile) => { +function setI18nDefaults(defaultI18n, collectionOrFile) { if (defaultI18n && collectionOrFile.has(I18N)) { const collectionOrFileI18n = collectionOrFile.get(I18N); if (collectionOrFileI18n === true) { @@ -121,17 +121,17 @@ const setI18nDefaults = (defaultI18n, collectionOrFile) => { } } return collectionOrFile; -}; +} -const throwOnInvalidFileCollectionStructure = i18n => { +function throwOnInvalidFileCollectionStructure(i18n) { if (i18n && i18n.get('structure') !== I18N_STRUCTURE.SINGLE_FILE) { throw new Error( `i18n configuration for files collections is limited to ${I18N_STRUCTURE.SINGLE_FILE} structure`, ); } -}; +} -const throwOnMissingDefaultLocale = i18n => { +function throwOnMissingDefaultLocale(i18n) { if (i18n && !i18n.get('locales').includes(i18n.get('default_locale'))) { throw new Error( `i18n locales '${i18n.get('locales').join(', ')}' are missing the default locale ${i18n.get( @@ -139,9 +139,9 @@ const throwOnMissingDefaultLocale = i18n => { )}`, ); } -}; +} -const setViewPatternsDefaults = (key, collection) => { +function setViewPatternsDefaults(key, collection) { if (!collection.has(key)) { collection = collection.set(key, fromJS([])); } else { @@ -152,17 +152,17 @@ const setViewPatternsDefaults = (key, collection) => { } return collection; -}; +} const defaults = { publish_mode: SIMPLE_PUBLISH_MODE, }; -const hasIntegration = (config, collection) => { +function hasIntegration(config, collection) { const integrations = getIntegrations(config); const integration = selectIntegration(integrations, collection.get('name'), 'listEntries'); return !!integration; -}; +} export function normalizeConfig(config) { const { collections = [] } = config; @@ -390,7 +390,7 @@ export async function detectProxyServer(localBackend) { return {}; } -const getPublishMode = (config, publishModes, backendType) => { +function getPublishMode(config, publishModes, backendType) { if (config.publish_mode && publishModes && !publishModes.includes(config.publish_mode)) { const newPublishMode = publishModes[0]; console.log( @@ -400,9 +400,9 @@ const getPublishMode = (config, publishModes, backendType) => { } return config.publish_mode; -}; +} -export const handleLocalBackend = async config => { +export async function handleLocalBackend(config) { if (!config.local_backend) { return config; } @@ -421,7 +421,7 @@ export const handleLocalBackend = async config => { ...(publishMode && { publish_mode: publishMode }), backend: { ...config.backend, name: 'proxy', proxy_url: proxyUrl }, }; -}; +} export function loadConfig(manualConfig = {}, onLoad) { if (window.CMS_CONFIG) { diff --git a/packages/netlify-cms-core/src/actions/entries.ts b/packages/netlify-cms-core/src/actions/entries.ts index 6cc32d4c..12493aa8 100644 --- a/packages/netlify-cms-core/src/actions/entries.ts +++ b/packages/netlify-cms-core/src/actions/entries.ts @@ -154,7 +154,7 @@ export function entriesFailed(collection: Collection, error: Error) { }; } -const getAllEntries = async (state: State, collection: Collection) => { +async function getAllEntries(state: State, collection: Collection) { const backend = currentBackend(state.config); const integration = selectIntegration(state, collection.get('name'), 'listEntries'); const provider: Backend = integration @@ -162,7 +162,7 @@ const getAllEntries = async (state: State, collection: Collection) => { : backend; const entries = await provider.listAllEntries(collection); return entries; -}; +} export function sortByField( collection: Collection, @@ -555,7 +555,7 @@ const appendActions = fromJS({ ['append_next']: { action: 'next', append: true }, }); -const addAppendActionsToCursor = (cursor: Cursor) => { +function addAppendActionsToCursor(cursor: Cursor) { return Cursor.create(cursor).updateStore('actions', (actions: Set) => { return actions.union( appendActions @@ -563,7 +563,7 @@ const addAppendActionsToCursor = (cursor: Cursor) => { .keySeq(), ); }); -}; +} export function loadEntries(collection: Collection, page = 0) { return async (dispatch: ThunkDispatch, getState: () => State) => { @@ -692,16 +692,16 @@ export function traverseCollectionCursor(collection: Collection, action: string) }; } -const escapeHtml = (unsafe: string) => { +function escapeHtml(unsafe: string) { return unsafe .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); -}; +} -const processValue = (unsafe: string) => { +function processValue(unsafe: string) { if (['true', 'True', 'TRUE'].includes(unsafe)) { return true; } @@ -710,10 +710,15 @@ const processValue = (unsafe: string) => { } return escapeHtml(unsafe); -}; +} -const getDataFields = (fields: EntryFields) => fields.filter(f => !f!.get('meta')).toList(); -const getMetaFields = (fields: EntryFields) => fields.filter(f => f!.get('meta') === true).toList(); +function getDataFields(fields: EntryFields) { + return fields.filter(f => !f!.get('meta')).toList(); +} + +function getMetaFields(fields: EntryFields) { + return fields.filter(f => f!.get('meta') === true).toList(); +} export function createEmptyDraft(collection: Collection, search: string) { return async (dispatch: ThunkDispatch, getState: () => State) => { @@ -785,7 +790,10 @@ export function createEmptyDraftData( const list = item.get('widget') == 'list'; const name = item.get('name'); const defaultValue = item.get('default', null); - const isEmptyDefaultValue = (val: unknown) => [[{}], {}].some(e => isEqual(val, e)); + + function isEmptyDefaultValue(val: unknown) { + return [[{}], {}].some(e => isEqual(val, e)); + } if (List.isList(subfields)) { const subDefaultValue = list @@ -831,9 +839,9 @@ function createEmptyDraftI18nData(collection: Collection, dataFields: EntryField return {}; } - const skipField = (field: EntryField) => { + function skipField(field: EntryField) { return field.get(I18N) !== I18N_FIELD.DUPLICATE && field.get(I18N) !== I18N_FIELD.TRANSLATE; - }; + } const i18nData = createEmptyDraftData(dataFields, true, skipField); return duplicateDefaultI18nFields(collection, i18nData); @@ -850,23 +858,25 @@ export function getMediaAssets({ entry }: { entry: EntryMap }) { return assets; } -export const getSerializedEntry = (collection: Collection, entry: Entry) => { +export function getSerializedEntry(collection: Collection, entry: Entry) { /** * Serialize the values of any fields with registered serializers, and * update the entry and entryDraft with the serialized values. */ const fields = selectFields(collection, entry.get('slug')); + // eslint-disable-next-line @typescript-eslint/no-explicit-any - const serializeData = (data: any) => { + function serializeData(data: any) { return serializeValues(data, fields); - }; + } + const serializedData = serializeData(entry.get('data')); let serializedEntry = entry.set('data', serializedData); if (hasI18n(collection)) { serializedEntry = serializeI18n(collection, serializedEntry, serializeData); } return serializedEntry; -}; +} export function persistEntry(collection: Collection) { return async (dispatch: ThunkDispatch, getState: () => State) => { @@ -982,11 +992,11 @@ export function deleteEntry(collection: Collection, slug: string) { }; } -const getPathError = ( +function getPathError( path: string | undefined, key: string, t: (key: string, args: Record) => string, -) => { +) { return { error: { type: ValidationErrorTypes.CUSTOM, @@ -995,7 +1005,7 @@ const getPathError = ( }), }, }; -}; +} export function validateMetaField( state: State, diff --git a/packages/netlify-cms-core/src/actions/media.ts b/packages/netlify-cms-core/src/actions/media.ts index 3d4033b9..152a355c 100644 --- a/packages/netlify-cms-core/src/actions/media.ts +++ b/packages/netlify-cms-core/src/actions/media.ts @@ -82,10 +82,10 @@ export function boundGetAsset( collection: Collection, entry: EntryMap, ) { - const bound = (path: string, field: EntryField) => { + function bound(path: string, field: EntryField) { const asset = dispatch(getAsset({ collection, entry, path, field })); return asset; - }; + } return bound; } diff --git a/packages/netlify-cms-core/src/actions/mediaLibrary.ts b/packages/netlify-cms-core/src/actions/mediaLibrary.ts index 4a013a50..9c6b1849 100644 --- a/packages/netlify-cms-core/src/actions/mediaLibrary.ts +++ b/packages/netlify-cms-core/src/actions/mediaLibrary.ts @@ -158,8 +158,8 @@ export function loadMedia( } dispatch(mediaLoading(page)); - const loadFunction = () => - backend + function loadFunction() { + return backend .getMedia() .then(files => dispatch(mediaLoaded(files))) .catch((error: { status?: number }) => { @@ -171,6 +171,7 @@ export function loadMedia( dispatch(mediaLoadFailed()); } }); + } if (delay > 0) { return new Promise(resolve => { diff --git a/packages/netlify-cms-core/src/actions/waitUntil.ts b/packages/netlify-cms-core/src/actions/waitUntil.ts index 338fca96..49f3b429 100644 --- a/packages/netlify-cms-core/src/actions/waitUntil.ts +++ b/packages/netlify-cms-core/src/actions/waitUntil.ts @@ -3,19 +3,19 @@ import { ThunkDispatch } from 'redux-thunk'; import { AnyAction } from 'redux'; import { State } from '../types/redux'; -export const waitUntil = ({ predicate, run }: WaitActionArgs) => { +export function waitUntil({ predicate, run }: WaitActionArgs) { return { type: WAIT_UNTIL_ACTION, predicate, run, }; -}; +} -export const waitUntilWithTimeout = async ( +export async function waitUntilWithTimeout( dispatch: ThunkDispatch, waitActionArgs: (resolve: (value?: T) => void) => WaitActionArgs, timeout = 30000, -): Promise => { +): Promise { let waitDone = false; const waitPromise = new Promise(resolve => { @@ -44,4 +44,4 @@ export const waitUntilWithTimeout = async ( ]); return result; -}; +} diff --git a/packages/netlify-cms-core/src/backend.ts b/packages/netlify-cms-core/src/backend.ts index 0516a2e6..7d359ee8 100644 --- a/packages/netlify-cms-core/src/backend.ts +++ b/packages/netlify-cms-core/src/backend.ts @@ -71,13 +71,13 @@ import { const { extractTemplateVars, dateParsers, expandPath } = stringTemplate; -const updateAssetProxies = ( +function updateAssetProxies( assetProxies: AssetProxy[], config: Config, collection: Collection, entryDraft: EntryDraft, path: string, -) => { +) { assetProxies.map(asset => { // update media files path based on entry path const oldPath = asset.path; @@ -90,7 +90,7 @@ const updateAssetProxies = ( ); asset.path = newPath; }); -}; +} export class LocalStorageAuthStore { storageKey = 'netlify-cms-user'; @@ -118,7 +118,7 @@ function getEntryBackupKey(collectionName?: string, slug?: string) { return `${baseKey}.${collectionName}${suffix}`; } -const getEntryField = (field: string, entry: EntryValue) => { +function getEntryField(field: string, entry: EntryValue) { const value = get(entry.data, field); if (value) { return String(value); @@ -131,19 +131,21 @@ const getEntryField = (field: string, entry: EntryValue) => { return ''; } } -}; +} -export const extractSearchFields = (searchFields: string[]) => (entry: EntryValue) => - searchFields.reduce((acc, field) => { - const value = getEntryField(field, entry); - if (value) { - return `${acc} ${value}`; - } else { - return acc; - } - }, ''); +export function extractSearchFields(searchFields: string[]) { + return (entry: EntryValue) => + searchFields.reduce((acc, field) => { + const value = getEntryField(field, entry); + if (value) { + return `${acc} ${value}`; + } else { + return acc; + } + }, ''); +} -export const expandSearchEntries = (entries: EntryValue[], searchFields: string[]) => { +export function expandSearchEntries(entries: EntryValue[], searchFields: string[]) { // expand the entries for the purpose of the search const expandedEntries = entries.reduce((acc, e) => { const expandedFields = searchFields.reduce((acc, f) => { @@ -160,9 +162,9 @@ export const expandSearchEntries = (entries: EntryValue[], searchFields: string[ }, [] as (EntryValue & { field: string })[]); return expandedEntries; -}; +} -export const mergeExpandedEntries = (entries: (EntryValue & { field: string })[]) => { +export function mergeExpandedEntries(entries: (EntryValue & { field: string })[]) { // merge the search results by slug and only keep data that matched the search const fields = entries.map(f => f.field); const arrayPaths: Record> = {}; @@ -214,20 +216,20 @@ export const mergeExpandedEntries = (entries: (EntryValue & { field: string })[] }); return Object.values(merged); -}; +} -const sortByScore = (a: fuzzy.FilterResult, b: fuzzy.FilterResult) => { +function sortByScore(a: fuzzy.FilterResult, b: fuzzy.FilterResult) { if (a.score > b.score) return -1; if (a.score < b.score) return 1; return 0; -}; +} -export const slugFromCustomPath = (collection: Collection, customPath: string) => { +export function slugFromCustomPath(collection: Collection, customPath: string) { const folderPath = collection.get('folder', '') as string; const entryPath = customPath.toLowerCase().replace(folderPath.toLowerCase(), ''); const slug = join(dirname(trim(entryPath, '/')), basename(entryPath, extname(customPath))); return slug; -}; +} interface AuthStore { retrieve: () => User; @@ -280,15 +282,15 @@ type Implementation = BackendImplementation & { init: (config: ImplementationConfig, options: ImplementationInitOptions) => Implementation; }; -const prepareMetaPath = (path: string, collection: Collection) => { +function prepareMetaPath(path: string, collection: Collection) { if (!selectHasMetaPath(collection)) { return path; } const dir = dirname(path); return dir.substr(collection.get('folder')!.length + 1) || '/'; -}; +} -const collectionDepth = (collection: Collection) => { +function collectionDepth(collection: Collection) { let depth; depth = collection.get('nested')?.get('depth') || getPathDepth(collection.get('path', '') as string); @@ -298,7 +300,7 @@ const collectionDepth = (collection: Collection) => { } return depth; -}; +} export class Backend { implementation: Implementation; diff --git a/packages/netlify-cms-core/src/bootstrap.js b/packages/netlify-cms-core/src/bootstrap.js index dfb4a978..dfca8b52 100644 --- a/packages/netlify-cms-core/src/bootstrap.js +++ b/packages/netlify-cms-core/src/bootstrap.js @@ -19,7 +19,7 @@ import 'what-input'; const ROOT_ID = 'nc-root'; -const TranslatedApp = ({ locale, config }) => { +function TranslatedApp({ locale, config }) { return ( @@ -29,11 +29,11 @@ const TranslatedApp = ({ locale, config }) => { ); -}; +} -const mapDispatchToProps = state => { +function mapDispatchToProps(state) { return { locale: selectLocale(state.config), config: state.config }; -}; +} const ConnectedTranslatedApp = connect(mapDispatchToProps)(TranslatedApp); @@ -82,14 +82,16 @@ function bootstrap(opts = {}) { /** * Create connected root component. */ - const Root = () => ( - <> - - - - - - ); + function Root() { + return ( + <> + + + + + + ); + } /** * Render application root. diff --git a/packages/netlify-cms-core/src/components/App/App.js b/packages/netlify-cms-core/src/components/App/App.js index f18bc5bb..d3ffb990 100644 --- a/packages/netlify-cms-core/src/components/App/App.js +++ b/packages/netlify-cms-core/src/components/App/App.js @@ -48,16 +48,16 @@ const ErrorCodeBlock = styled.pre` line-height: 1.5; `; -const getDefaultPath = collections => { +function getDefaultPath(collections) { const first = collections.filter(collection => collection.get('hide') !== true).first(); if (first) { return `/collections/${first.get('name')}`; } else { throw new Error('Could not find a non hidden collection'); } -}; +} -const RouteInCollection = ({ collections, render, ...props }) => { +function RouteInCollection({ collections, render, ...props }) { const defaultPath = getDefaultPath(collections); return ( { }} /> ); -}; +} class App extends React.Component { static propTypes = { diff --git a/packages/netlify-cms-core/src/components/App/Header.js b/packages/netlify-cms-core/src/components/App/Header.js index 2b90e30b..86adf895 100644 --- a/packages/netlify-cms-core/src/components/App/Header.js +++ b/packages/netlify-cms-core/src/components/App/Header.js @@ -26,20 +26,22 @@ const styles = { `, }; -const AppHeader = props => ( -
-); +function AppHeader(props) { + return ( +
+ ); +} const AppHeaderContent = styled.div` display: flex; diff --git a/packages/netlify-cms-core/src/components/App/NotFoundPage.js b/packages/netlify-cms-core/src/components/App/NotFoundPage.js index 917bffbe..ff93df34 100644 --- a/packages/netlify-cms-core/src/components/App/NotFoundPage.js +++ b/packages/netlify-cms-core/src/components/App/NotFoundPage.js @@ -8,11 +8,13 @@ const NotFoundContainer = styled.div` margin: ${lengths.pageMargin}; `; -const NotFoundPage = ({ t }) => ( - -

{t('app.notFoundPage.header')}

-
-); +function NotFoundPage({ t }) { + return ( + +

{t('app.notFoundPage.header')}

+
+ ); +} NotFoundPage.propTypes = { t: PropTypes.func.isRequired, diff --git a/packages/netlify-cms-core/src/components/Collection/Collection.js b/packages/netlify-cms-core/src/components/Collection/Collection.js index 5b014502..c956dac3 100644 --- a/packages/netlify-cms-core/src/components/Collection/Collection.js +++ b/packages/netlify-cms-core/src/components/Collection/Collection.js @@ -183,7 +183,7 @@ const mapDispatchToProps = { groupByField, }; -const mergeProps = (stateProps, dispatchProps, ownProps) => { +function mergeProps(stateProps, dispatchProps, ownProps) { return { ...stateProps, ...ownProps, @@ -193,7 +193,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { onGroupClick: group => dispatchProps.groupByField(stateProps.collection, group), onChangeViewStyle: viewStyle => dispatchProps.changeViewStyle(viewStyle), }; -}; +} const ConnectedCollection = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Collection); diff --git a/packages/netlify-cms-core/src/components/Collection/CollectionControls.js b/packages/netlify-cms-core/src/components/Collection/CollectionControls.js index 006ffdc6..9e912113 100644 --- a/packages/netlify-cms-core/src/components/Collection/CollectionControls.js +++ b/packages/netlify-cms-core/src/components/Collection/CollectionControls.js @@ -19,7 +19,7 @@ const CollectionControlsContainer = styled.div` } `; -const CollectionControls = ({ +function CollectionControls({ viewStyle, onChangeViewStyle, sortableFields, @@ -32,7 +32,7 @@ const CollectionControls = ({ t, filter, group, -}) => { +}) { return ( @@ -52,6 +52,6 @@ const CollectionControls = ({ )} ); -}; +} export default CollectionControls; diff --git a/packages/netlify-cms-core/src/components/Collection/CollectionTop.js b/packages/netlify-cms-core/src/components/Collection/CollectionTop.js index 48e04cb2..5d5a8c3b 100644 --- a/packages/netlify-cms-core/src/components/Collection/CollectionTop.js +++ b/packages/netlify-cms-core/src/components/Collection/CollectionTop.js @@ -35,7 +35,7 @@ const CollectionTopDescription = styled.p` margin-bottom: 0; `; -const getCollectionProps = collection => { +function getCollectionProps(collection) { const collectionLabel = collection.get('label'); const collectionLabelSingular = collection.get('label_singular'); const collectionDescription = collection.get('description'); @@ -45,9 +45,9 @@ const getCollectionProps = collection => { collectionLabelSingular, collectionDescription, }; -}; +} -const CollectionTop = ({ collection, newEntryUrl, t }) => { +function CollectionTop({ collection, newEntryUrl, t }) { const { collectionLabel, collectionLabelSingular, collectionDescription } = getCollectionProps( collection, t, @@ -70,7 +70,7 @@ const CollectionTop = ({ collection, newEntryUrl, t }) => { ) : null} ); -}; +} CollectionTop.propTypes = { collection: ImmutablePropTypes.map.isRequired, diff --git a/packages/netlify-cms-core/src/components/Collection/ControlButton.js b/packages/netlify-cms-core/src/components/Collection/ControlButton.js index 809a42e2..848e3bfc 100644 --- a/packages/netlify-cms-core/src/components/Collection/ControlButton.js +++ b/packages/netlify-cms-core/src/components/Collection/ControlButton.js @@ -14,7 +14,7 @@ const Button = styled(StyledDropdownButton)` } `; -export const ControlButton = ({ active, title }) => { +export function ControlButton({ active, title }) { return ( ); -}; +} diff --git a/packages/netlify-cms-core/src/components/Collection/Entries/Entries.js b/packages/netlify-cms-core/src/components/Collection/Entries/Entries.js index 40991041..17b39485 100644 --- a/packages/netlify-cms-core/src/components/Collection/Entries/Entries.js +++ b/packages/netlify-cms-core/src/components/Collection/Entries/Entries.js @@ -16,7 +16,7 @@ const NoEntriesMessage = styled(PaginationMessage)` margin-top: 16px; `; -const Entries = ({ +function Entries({ collections, entries, isFetching, @@ -25,7 +25,7 @@ const Entries = ({ handleCursorActions, t, page, -}) => { +}) { const loadingMessages = [ t('collection.entries.loadingEntries'), t('collection.entries.cachingEntries'), @@ -56,7 +56,7 @@ const Entries = ({ } return {t('collection.entries.noEntries')}; -}; +} Entries.propTypes = { collections: ImmutablePropTypes.iterable.isRequired, diff --git a/packages/netlify-cms-core/src/components/Collection/Entries/EntriesCollection.js b/packages/netlify-cms-core/src/components/Collection/Entries/EntriesCollection.js index f8acf94e..12be141b 100644 --- a/packages/netlify-cms-core/src/components/Collection/Entries/EntriesCollection.js +++ b/packages/netlify-cms-core/src/components/Collection/Entries/EntriesCollection.js @@ -28,11 +28,11 @@ const GroupHeading = styled.h2` const GroupContainer = styled.div``; -const getGroupEntries = (entries, paths) => { +function getGroupEntries(entries, paths) { return entries.filter(entry => paths.has(entry.get('path'))); -}; +} -const getGroupTitle = (group, t) => { +function getGroupTitle(group, t) { const { label, value } = group; if (value === undefined) { return t('collection.groups.other'); @@ -41,9 +41,9 @@ const getGroupTitle = (group, t) => { return value ? label : t('collection.groups.negateLabel', { label }); } return `${label} ${value}`.trim(); -}; +} -const withGroups = (groups, entries, EntriesToRender, t) => { +function withGroups(groups, entries, EntriesToRender, t) { return groups.map(group => { const title = getGroupTitle(group, t); return ( @@ -53,7 +53,7 @@ const withGroups = (groups, entries, EntriesToRender, t) => { ); }); -}; +} export class EntriesCollection extends React.Component { static propTypes = { @@ -114,7 +114,7 @@ export class EntriesCollection extends React.Component { } } -export const filterNestedEntries = (path, collectionFolder, entries) => { +export function filterNestedEntries(path, collectionFolder, entries) { const filtered = entries.filter(e => { const entryPath = e.get('path').substring(collectionFolder.length + 1); if (!entryPath.startsWith(path)) { @@ -132,7 +132,7 @@ export const filterNestedEntries = (path, collectionFolder, entries) => { } }); return filtered; -}; +} function mapStateToProps(state, ownProps) { const { collection, viewStyle, filterTerm } = ownProps; diff --git a/packages/netlify-cms-core/src/components/Collection/Entries/EntryCard.js b/packages/netlify-cms-core/src/components/Collection/Entries/EntryCard.js index d96a587c..24192bb2 100644 --- a/packages/netlify-cms-core/src/components/Collection/Entries/EntryCard.js +++ b/packages/netlify-cms-core/src/components/Collection/Entries/EntryCard.js @@ -84,7 +84,7 @@ const CardImage = styled.div` height: 150px; `; -const EntryCard = ({ +function EntryCard({ path, summary, image, @@ -92,7 +92,7 @@ const EntryCard = ({ collectionLabel, viewStyle = VIEW_STYLE_LIST, getAsset, -}) => { +}) { if (viewStyle === VIEW_STYLE_LIST) { return ( @@ -117,9 +117,9 @@ const EntryCard = ({ ); } -}; +} -const mapStateToProps = (state, ownProps) => { +function mapStateToProps(state, ownProps) { const { entry, inferedFields, collection } = ownProps; const entryData = entry.get('data'); const summary = selectEntryCollectionTitle(collection, entry); @@ -140,22 +140,22 @@ const mapStateToProps = (state, ownProps) => { ?.find(f => f.get('name') === inferedFields.imageField && f.get('widget') === 'image'), isLoadingAsset, }; -}; +} -const mapDispatchToProps = dispatch => { +function mapDispatchToProps(dispatch) { return { boundGetAsset: (collection, entry) => boundGetAsset(dispatch, collection, entry), }; -}; +} -const mergeProps = (stateProps, dispatchProps, ownProps) => { +function mergeProps(stateProps, dispatchProps, ownProps) { return { ...stateProps, ...dispatchProps, ...ownProps, getAsset: dispatchProps.boundGetAsset(ownProps.collection, ownProps.entry), }; -}; +} const ConnectedEntryCard = connect(mapStateToProps, mapDispatchToProps, mergeProps)(EntryCard); diff --git a/packages/netlify-cms-core/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js b/packages/netlify-cms-core/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js index c44df1e2..624dbca2 100644 --- a/packages/netlify-cms-core/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js +++ b/packages/netlify-cms-core/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js @@ -13,14 +13,15 @@ jest.mock('../Entries', () => 'mock-entries'); const middlewares = []; const mockStore = configureStore(middlewares); -const renderWithRedux = (component, { store } = {}) => { +function renderWithRedux(component, { store } = {}) { function Wrapper({ children }) { return {children}; } - return render(component, { wrapper: Wrapper }); -}; -const toEntriesState = (collection, entriesArray) => { + return render(component, { wrapper: Wrapper }); +} + +function toEntriesState(collection, entriesArray) { const entries = entriesArray.reduce( (acc, entry) => { acc.entities[`${collection.get('name')}.${entry.slug}`] = entry; @@ -30,7 +31,7 @@ const toEntriesState = (collection, entriesArray) => { { pages: { [collection.get('name')]: { ids: [] } }, entities: {} }, ); return fromJS(entries); -}; +} describe('filterNestedEntries', () => { it('should return only immediate children for non root path', () => { diff --git a/packages/netlify-cms-core/src/components/Collection/FilterControl.js b/packages/netlify-cms-core/src/components/Collection/FilterControl.js index 40cf3c71..129554b9 100644 --- a/packages/netlify-cms-core/src/components/Collection/FilterControl.js +++ b/packages/netlify-cms-core/src/components/Collection/FilterControl.js @@ -3,7 +3,7 @@ import { translate } from 'react-polyglot'; import { Dropdown, DropdownCheckedItem } from 'netlify-cms-ui-default'; import { ControlButton } from './ControlButton'; -const FilterControl = ({ viewFilters, t, onFilterClick, filter }) => { +function FilterControl({ viewFilters, t, onFilterClick, filter }) { const hasActiveFilter = filter ?.valueSeq() .toJS() @@ -33,6 +33,6 @@ const FilterControl = ({ viewFilters, t, onFilterClick, filter }) => { })} ); -}; +} export default translate()(FilterControl); diff --git a/packages/netlify-cms-core/src/components/Collection/GroupControl.js b/packages/netlify-cms-core/src/components/Collection/GroupControl.js index b6b5537b..abcd3118 100644 --- a/packages/netlify-cms-core/src/components/Collection/GroupControl.js +++ b/packages/netlify-cms-core/src/components/Collection/GroupControl.js @@ -3,7 +3,7 @@ import { translate } from 'react-polyglot'; import { Dropdown, DropdownItem } from 'netlify-cms-ui-default'; import { ControlButton } from './ControlButton'; -const GroupControl = ({ viewGroups, t, onGroupClick, group }) => { +function GroupControl({ viewGroups, t, onGroupClick, group }) { const hasActiveGroup = group ?.valueSeq() .toJS() @@ -33,6 +33,6 @@ const GroupControl = ({ viewGroups, t, onGroupClick, group }) => { })} ); -}; +} export default translate()(GroupControl); diff --git a/packages/netlify-cms-core/src/components/Collection/NestedCollection.js b/packages/netlify-cms-core/src/components/Collection/NestedCollection.js index cfb25ef1..4047da72 100644 --- a/packages/netlify-cms-core/src/components/Collection/NestedCollection.js +++ b/packages/netlify-cms-core/src/components/Collection/NestedCollection.js @@ -66,14 +66,14 @@ const TreeNavLink = styled(NavLink)` `}; `; -const getNodeTitle = node => { +function getNodeTitle(node) { const title = node.isRoot ? node.title : node.children.find(c => !c.isDir && c.title)?.title || node.title; return title; -}; +} -const TreeNode = props => { +function TreeNode(props) { const { collection, treeData, depth = 0, onToggle } = props; const collectionName = collection.get('name'); @@ -118,7 +118,7 @@ const TreeNode = props => { ); }); -}; +} TreeNode.propTypes = { collection: ImmutablePropTypes.map.isRequired, @@ -127,18 +127,18 @@ TreeNode.propTypes = { onToggle: PropTypes.func.isRequired, }; -export const walk = (treeData, callback) => { - const traverse = children => { +export function walk(treeData, callback) { + function traverse(children) { for (const child of children) { callback(child); traverse(child.children); } - }; + } return traverse(treeData); -}; +} -export const getTreeData = (collection, entries) => { +export function getTreeData(collection, entries) { const collectionFolder = collection.get('folder'); const rootFolder = '/'; const entriesObj = entries @@ -200,7 +200,7 @@ export const getTreeData = (collection, entries) => { return acc; }, {}); - const reducer = (acc, value) => { + function reducer(acc, value) { const node = value; let children = []; if (parentsToChildren[node.path]) { @@ -209,17 +209,17 @@ export const getTreeData = (collection, entries) => { acc.push({ ...node, children }); return acc; - }; + } const treeData = parentsToChildren[''].reduce(reducer, []); return treeData; -}; +} -export const updateNode = (treeData, node, callback) => { +export function updateNode(treeData, node, callback) { let stop = false; - const updater = nodes => { + function updater(nodes) { if (stop) { return nodes; } @@ -232,10 +232,10 @@ export const updateNode = (treeData, node, callback) => { } nodes.forEach(node => updater(node.children)); return nodes; - }; + } return updater([...treeData]); -}; +} export class NestedCollection extends React.Component { static propTypes = { diff --git a/packages/netlify-cms-core/src/components/Collection/SortControl.js b/packages/netlify-cms-core/src/components/Collection/SortControl.js index fb1095c3..5624ee32 100644 --- a/packages/netlify-cms-core/src/components/Collection/SortControl.js +++ b/packages/netlify-cms-core/src/components/Collection/SortControl.js @@ -28,7 +28,7 @@ const sortIconDirections = { [SortDirection.Descending]: 'down', }; -const SortControl = ({ t, fields, onSortClick, sort }) => { +function SortControl({ t, fields, onSortClick, sort }) { const hasActiveSort = sort ?.valueSeq() .toJS() @@ -62,6 +62,6 @@ const SortControl = ({ t, fields, onSortClick, sort }) => { })} ); -}; +} export default translate()(SortControl); diff --git a/packages/netlify-cms-core/src/components/Collection/ViewStyleControl.js b/packages/netlify-cms-core/src/components/Collection/ViewStyleControl.js index 1bad4a7a..444f9f1b 100644 --- a/packages/netlify-cms-core/src/components/Collection/ViewStyleControl.js +++ b/packages/netlify-cms-core/src/components/Collection/ViewStyleControl.js @@ -27,7 +27,7 @@ const ViewControlsButton = styled.button` } `; -const ViewStyleControl = ({ viewStyle, onChangeViewStyle }) => { +function ViewStyleControl({ viewStyle, onChangeViewStyle }) { return ( { ); -}; +} export default ViewStyleControl; diff --git a/packages/netlify-cms-core/src/components/Collection/__tests__/Collection.spec.js b/packages/netlify-cms-core/src/components/Collection/__tests__/Collection.spec.js index e8f24e48..f40b76ee 100644 --- a/packages/netlify-cms-core/src/components/Collection/__tests__/Collection.spec.js +++ b/packages/netlify-cms-core/src/components/Collection/__tests__/Collection.spec.js @@ -13,12 +13,13 @@ jest.mock('../Sidebar', () => 'mock-sidebar'); const middlewares = []; const mockStore = configureStore(middlewares); -const renderWithRedux = (component, { store } = {}) => { +function renderWithRedux(component, { store } = {}) { function Wrapper({ children }) { return {children}; } + return render(component, { wrapper: Wrapper }); -}; +} describe('Collection', () => { const collection = fromJS({ diff --git a/packages/netlify-cms-core/src/components/Collection/__tests__/NestedCollection.spec.js b/packages/netlify-cms-core/src/components/Collection/__tests__/NestedCollection.spec.js index e31cbcae..c9fdeb54 100644 --- a/packages/netlify-cms-core/src/components/Collection/__tests__/NestedCollection.spec.js +++ b/packages/netlify-cms-core/src/components/Collection/__tests__/NestedCollection.spec.js @@ -22,12 +22,13 @@ jest.mock('netlify-cms-ui-default', () => { const middlewares = []; const mockStore = configureStore(middlewares); -const renderWithRedux = (component, { store } = {}) => { +function renderWithRedux(component, { store } = {}) { function Wrapper({ children }) { return {children}; } + return render(component, { wrapper: Wrapper }); -}; +} describe('NestedCollection', () => { const collection = fromJS({ diff --git a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControl.js b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControl.js index 6634cec9..056ae5df 100644 --- a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControl.js +++ b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControl.js @@ -95,7 +95,7 @@ export const ControlHint = styled.p` transition: color ${transitions.main}; `; -const LabelComponent = ({ field, isActive, hasErrors, uniqueFieldId, isFieldOptional, t }) => { +function LabelComponent({ field, isActive, hasErrors, uniqueFieldId, isFieldOptional, t }) { const label = `${field.get('label', field.get('name'))}`; const labelComponent = ( @@ -104,7 +104,7 @@ const LabelComponent = ({ field, isActive, hasErrors, uniqueFieldId, isFieldOpti ); return labelComponent; -}; +} class EditorControl extends React.Component { static propTypes = { @@ -334,13 +334,13 @@ class EditorControl extends React.Component { } } -const mapStateToProps = state => { +function mapStateToProps(state) { const { collections, entryDraft } = state; const entry = entryDraft.get('entry'); const collection = collections.get(entryDraft.getIn(['entry', 'collection'])); const isLoadingAsset = selectIsLoadingAsset(state.medias); - const loadEntry = async (collectionName, slug) => { + async function loadEntry(collectionName, slug) { const targetCollection = collections.get(collectionName); if (targetCollection) { const loadedEntry = await tryLoadEntry(state, targetCollection, slug); @@ -348,7 +348,7 @@ const mapStateToProps = state => { } else { throw new Error(`Can't find collection '${collectionName}'`); } - }; + } return { mediaPaths: state.mediaLibrary.get('controlMedia'), @@ -361,9 +361,9 @@ const mapStateToProps = state => { loadEntry, validateMetaField: (field, value, t) => validateMetaField(state, collection, field, value, t), }; -}; +} -const mapDispatchToProps = dispatch => { +function mapDispatchToProps(dispatch) { const creators = bindActionCreators( { openMediaLibrary, @@ -381,16 +381,16 @@ const mapDispatchToProps = dispatch => { ...creators, boundGetAsset: (collection, entry) => boundGetAsset(dispatch, collection, entry), }; -}; +} -const mergeProps = (stateProps, dispatchProps, ownProps) => { +function mergeProps(stateProps, dispatchProps, ownProps) { return { ...stateProps, ...dispatchProps, ...ownProps, boundGetAsset: dispatchProps.boundGetAsset(stateProps.collection, stateProps.entry), }; -}; +} const ConnectedEditorControl = connect( mapStateToProps, diff --git a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControlPane.js b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControlPane.js index 8c54e522..7eb39199 100644 --- a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControlPane.js +++ b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControlPane.js @@ -50,7 +50,7 @@ const StyledDropdown = styled(Dropdown)` margin-bottom: 20px; `; -const LocaleDropdown = ({ locales, selectedLocale, onLocaleChange, t }) => { +function LocaleDropdown({ locales, selectedLocale, onLocaleChange, t }) { return ( { @@ -77,9 +77,9 @@ const LocaleDropdown = ({ locales, selectedLocale, onLocaleChange, t }) => { ))} ); -}; +} -const getFieldValue = ({ field, entry, isTranslatable, locale }) => { +function getFieldValue({ field, entry, isTranslatable, locale }) { if (field.get('meta')) { return entry.getIn(['meta', field.get('name')]); } @@ -90,7 +90,7 @@ const getFieldValue = ({ field, entry, isTranslatable, locale }) => { } return entry.getIn(['data', field.get('name')]); -}; +} export default class ControlPane extends React.Component { state = { diff --git a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/Widget.js b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/Widget.js index cde7cd69..25956126 100644 --- a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/Widget.js +++ b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/Widget.js @@ -5,14 +5,19 @@ import { Map, List } from 'immutable'; import { oneLine } from 'common-tags'; import ValidationErrorTypes from 'Constants/validationErrorTypes'; -const truthy = () => ({ error: false }); +function truthy() { + return { error: false }; +} -const isEmpty = value => - value === null || - value === undefined || - (Object.prototype.hasOwnProperty.call(value, 'length') && value.length === 0) || - (value.constructor === Object && Object.keys(value).length === 0) || - (List.isList(value) && value.size === 0); +function isEmpty(value) { + return ( + value === null || + value === undefined || + (Object.prototype.hasOwnProperty.call(value, 'length') && value.length === 0) || + (value.constructor === Object && Object.keys(value).length === 0) || + (List.isList(value) && value.size === 0) + ); +} export default class Widget extends Component { static propTypes = { diff --git a/packages/netlify-cms-core/src/components/Editor/EditorInterface.js b/packages/netlify-cms-core/src/components/Editor/EditorInterface.js index 2e21674d..7007a0ea 100644 --- a/packages/netlify-cms-core/src/components/Editor/EditorInterface.js +++ b/packages/netlify-cms-core/src/components/Editor/EditorInterface.js @@ -41,33 +41,35 @@ const EditorToggle = styled(IconButton)` margin-bottom: 12px; `; -const ReactSplitPaneGlobalStyles = () => ( - -); + `} + /> + ); +} const StyledSplitPane = styled(SplitPane)` ${styles.splitPane}; @@ -121,13 +123,13 @@ const ViewControls = styled.div` z-index: ${zIndex.zIndex299}; `; -const EditorContent = ({ +function EditorContent({ i18nVisible, previewVisible, editor, editorWithEditor, editorWithPreview, -}) => { +}) { if (i18nVisible) { return editorWithEditor; } else if (previewVisible) { @@ -135,7 +137,7 @@ const EditorContent = ({ } else { return {editor}; } -}; +} function isPreviewEnabled(collection, entry) { if (collection.get('type') === FILES) { diff --git a/packages/netlify-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js b/packages/netlify-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js index 003f92ee..1692a962 100644 --- a/packages/netlify-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js +++ b/packages/netlify-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js @@ -248,24 +248,24 @@ PreviewPane.propTypes = { getAsset: PropTypes.func.isRequired, }; -const mapStateToProps = state => { +function mapStateToProps(state) { const isLoadingAsset = selectIsLoadingAsset(state.medias); return { isLoadingAsset, config: state.config }; -}; +} -const mapDispatchToProps = dispatch => { +function mapDispatchToProps(dispatch) { return { boundGetAsset: (collection, entry) => boundGetAsset(dispatch, collection, entry), }; -}; +} -const mergeProps = (stateProps, dispatchProps, ownProps) => { +function mergeProps(stateProps, dispatchProps, ownProps) { return { ...stateProps, ...dispatchProps, ...ownProps, getAsset: dispatchProps.boundGetAsset(ownProps.collection, ownProps.entry), }; -}; +} export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(PreviewPane); diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/Unknown/UnknownControl.js b/packages/netlify-cms-core/src/components/EditorWidgets/Unknown/UnknownControl.js index 20cb27e4..638b9ea6 100644 --- a/packages/netlify-cms-core/src/components/EditorWidgets/Unknown/UnknownControl.js +++ b/packages/netlify-cms-core/src/components/EditorWidgets/Unknown/UnknownControl.js @@ -3,11 +3,11 @@ import { translate } from 'react-polyglot'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; -const UnknownControl = ({ field, t }) => { +function UnknownControl({ field, t }) { return (
{t('editor.editorWidgets.unknownControl.noControl', { widget: field.get('widget') })}
); -}; +} UnknownControl.propTypes = { field: ImmutablePropTypes.map, diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/Unknown/UnknownPreview.js b/packages/netlify-cms-core/src/components/EditorWidgets/Unknown/UnknownPreview.js index 4ac2cb89..44a8ec0b 100644 --- a/packages/netlify-cms-core/src/components/EditorWidgets/Unknown/UnknownPreview.js +++ b/packages/netlify-cms-core/src/components/EditorWidgets/Unknown/UnknownPreview.js @@ -3,13 +3,13 @@ import { translate } from 'react-polyglot'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; -const UnknownPreview = ({ field, t }) => { +function UnknownPreview({ field, t }) { return (
{t('editor.editorWidgets.unknownPreview.noPreview', { widget: field.get('widget') })}
); -}; +} UnknownPreview.propTypes = { field: ImmutablePropTypes.map, diff --git a/packages/netlify-cms-core/src/components/MediaLibrary/EmptyMessage.js b/packages/netlify-cms-core/src/components/MediaLibrary/EmptyMessage.js index 04725b94..5890d6e9 100644 --- a/packages/netlify-cms-core/src/components/MediaLibrary/EmptyMessage.js +++ b/packages/netlify-cms-core/src/components/MediaLibrary/EmptyMessage.js @@ -12,11 +12,13 @@ const EmptyMessageContainer = styled.div` color: ${props => props.isPrivate && colors.textFieldBorder}; `; -const EmptyMessage = ({ content, isPrivate }) => ( - -

{content}

-
-); +function EmptyMessage({ content, isPrivate }) { + return ( + +

{content}

+
+ ); +} EmptyMessage.propTypes = { content: PropTypes.string.isRequired, diff --git a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibrary.js b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibrary.js index a3d39477..b0eba307 100644 --- a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibrary.js +++ b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibrary.js @@ -354,7 +354,7 @@ class MediaLibrary extends React.Component { } } -const mapStateToProps = state => { +function mapStateToProps(state) { const { mediaLibrary } = state; const field = mediaLibrary.get('field'); const mediaLibraryProps = { @@ -377,7 +377,7 @@ const mapStateToProps = state => { field, }; return { ...mediaLibraryProps }; -}; +} const mapDispatchToProps = { loadMedia: loadMediaAction, diff --git a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryCardGrid.js b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryCardGrid.js index a27ec31f..5aeae896 100644 --- a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryCardGrid.js +++ b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryCardGrid.js @@ -8,7 +8,7 @@ import { colors } from 'netlify-cms-ui-default'; import { FixedSizeGrid as Grid } from 'react-window'; import AutoSizer from 'react-virtualized-auto-sizer'; -const CardWrapper = props => { +function CardWrapper(props) { const { rowIndex, columnIndex, @@ -61,9 +61,9 @@ const CardWrapper = props => { /> ); -}; +} -const VirtualizedGrid = props => { +function VirtualizedGrid(props) { const { mediaItems, setScrollContainerRef } = props; return ( @@ -94,9 +94,9 @@ const VirtualizedGrid = props => { ); -}; +} -const PaginatedGrid = ({ +function PaginatedGrid({ setScrollContainerRef, mediaItems, isSelectedFile, @@ -112,7 +112,7 @@ const PaginatedGrid = ({ onLoadMore, isPaginating, paginatingMessage, -}) => { +}) { return ( @@ -141,7 +141,7 @@ const PaginatedGrid = ({ )} ); -}; +} const CardGridContainer = styled.div` overflow-y: auto; @@ -160,13 +160,13 @@ const PaginatingMessage = styled.h1` color: ${props => props.isPrivate && colors.textFieldBorder}; `; -const MediaLibraryCardGrid = props => { +function MediaLibraryCardGrid(props) { const { canLoadMore, isPaginating } = props; if (canLoadMore || isPaginating) { return ; } return ; -}; +} MediaLibraryCardGrid.propTypes = { setScrollContainerRef: PropTypes.func.isRequired, diff --git a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryHeader.js b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryHeader.js index 103b4702..fe354ab8 100644 --- a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryHeader.js +++ b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryHeader.js @@ -28,14 +28,16 @@ const LibraryTitle = styled.h1` color: ${props => props.isPrivate && colors.textFieldBorder}; `; -const MediaLibraryHeader = ({ onClose, title, isPrivate }) => ( -
- - - - {title} -
-); +function MediaLibraryHeader({ onClose, title, isPrivate }) { + return ( +
+ + + + {title} +
+ ); +} MediaLibraryHeader.propTypes = { onClose: PropTypes.func.isRequired, diff --git a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryModal.js b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryModal.js index a6ffe363..ac25b493 100644 --- a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryModal.js +++ b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryModal.js @@ -60,7 +60,7 @@ const StyledModal = styled(Modal)` } `; -const MediaLibraryModal = ({ +function MediaLibraryModal({ isVisible, canInsert, files, @@ -91,7 +91,7 @@ const MediaLibraryModal = ({ loadDisplayURL, displayURLs, t, -}) => { +}) { const filteredFiles = forImage ? handleFilter(files) : files; const queriedFiles = !dynamicSearch && query ? handleQuery(query, filteredFiles) : filteredFiles; const tableData = toTableData(queriedFiles); @@ -152,7 +152,7 @@ const MediaLibraryModal = ({ /> ); -}; +} export const fileShape = { displayURL: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, diff --git a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibrarySearch.js b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibrarySearch.js index c2be293f..9c188adf 100644 --- a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibrarySearch.js +++ b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibrarySearch.js @@ -35,18 +35,20 @@ const SearchIcon = styled(Icon)` transform: translate(0, -50%); `; -const MediaLibrarySearch = ({ value, onChange, onKeyDown, placeholder, disabled }) => ( - - - - -); +function MediaLibrarySearch({ value, onChange, onKeyDown, placeholder, disabled }) { + return ( + + + + + ); +} MediaLibrarySearch.propTypes = { value: PropTypes.string, diff --git a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryTop.js b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryTop.js index b0350482..f9e9b6cd 100644 --- a/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryTop.js +++ b/packages/netlify-cms-core/src/components/MediaLibrary/MediaLibraryTop.js @@ -26,7 +26,7 @@ const ButtonsContainer = styled.div` flex-shrink: 0; `; -const MediaLibraryTop = ({ +function MediaLibraryTop({ t, onClose, privateUpload, @@ -44,7 +44,7 @@ const MediaLibraryTop = ({ isPersisting, isDeleting, selectedFile, -}) => { +}) { const shouldShowButtonLoader = isPersisting || isDeleting; const uploadEnabled = !shouldShowButtonLoader; const deleteEnabled = !shouldShowButtonLoader && hasSelection; @@ -110,7 +110,7 @@ const MediaLibraryTop = ({ ); -}; +} MediaLibraryTop.propTypes = { t: PropTypes.func.isRequired, diff --git a/packages/netlify-cms-core/src/components/UI/DragDrop.js b/packages/netlify-cms-core/src/components/UI/DragDrop.js index 0e86a61a..c02f6b77 100644 --- a/packages/netlify-cms-core/src/components/UI/DragDrop.js +++ b/packages/netlify-cms-core/src/components/UI/DragDrop.js @@ -7,7 +7,7 @@ import { import React from 'react'; import PropTypes from 'prop-types'; -export const DragSource = ({ namespace, ...props }) => { +export function DragSource({ namespace, ...props }) { const DragComponent = ReactDNDDragSource( namespace, { @@ -23,13 +23,14 @@ export const DragSource = ({ namespace, ...props }) => { )(({ children, connectDragComponent }) => children(connectDragComponent)); return React.createElement(DragComponent, props, props.children); -}; +} + DragSource.propTypes = { namespace: PropTypes.any.isRequired, children: PropTypes.func.isRequired, }; -export const DropTarget = ({ onDrop, namespace, ...props }) => { +export function DropTarget({ onDrop, namespace, ...props }) { const DropComponent = ReactDNDDropTarget( namespace, { @@ -44,11 +45,14 @@ export const DropTarget = ({ onDrop, namespace, ...props }) => { )(({ children, connectDropTarget, isHovered }) => children(connectDropTarget, { isHovered })); return React.createElement(DropComponent, props, props.children); -}; +} + DropTarget.propTypes = { onDrop: PropTypes.func.isRequired, namespace: PropTypes.any.isRequired, children: PropTypes.func.isRequired, }; -export const HTML5DragDrop = component => ReactDNDDragDropContext(ReactDNDHTML5Backend)(component); +export function HTML5DragDrop(component) { + return ReactDNDDragDropContext(ReactDNDHTML5Backend)(component); +} diff --git a/packages/netlify-cms-core/src/components/UI/ErrorBoundary.js b/packages/netlify-cms-core/src/components/UI/ErrorBoundary.js index 455c7b09..d8c7e27c 100644 --- a/packages/netlify-cms-core/src/components/UI/ErrorBoundary.js +++ b/packages/netlify-cms-core/src/components/UI/ErrorBoundary.js @@ -10,7 +10,9 @@ import { localForage } from 'netlify-cms-lib-util'; import { buttons, colors } from 'netlify-cms-ui-default'; const ISSUE_URL = 'https://github.com/netlify/netlify-cms/issues/new?'; -const getIssueTemplate = ({ version, provider, browser, config }) => ` + +function getIssueTemplate({ version, provider, browser, config }) { + return ` **Describe the bug** **To Reproduce** @@ -31,8 +33,9 @@ ${config} **Additional context** `; +} -const buildIssueTemplate = ({ config }) => { +function buildIssueTemplate({ config }) { let version = ''; if (typeof NETLIFY_CMS_VERSION === 'string') { version = `netlify-cms@${NETLIFY_CMS_VERSION}`; @@ -47,9 +50,9 @@ const buildIssueTemplate = ({ config }) => { }); return template; -}; +} -const buildIssueUrl = ({ title, config }) => { +function buildIssueUrl({ title, config }) { try { const body = buildIssueTemplate({ config }); @@ -63,7 +66,7 @@ const buildIssueUrl = ({ title, config }) => { console.log(e); return `${ISSUE_URL}template=bug_report.md`; } -}; +} const ErrorBoundaryContainer = styled.div` padding: 40px; @@ -107,7 +110,7 @@ const CopyButton = styled.button` margin: 12px 0; `; -const RecoveredEntry = ({ entry, t }) => { +function RecoveredEntry({ entry, t }) { console.log(entry); return ( <> @@ -122,7 +125,7 @@ const RecoveredEntry = ({ entry, t }) => { ); -}; +} export class ErrorBoundary extends React.Component { static propTypes = { diff --git a/packages/netlify-cms-core/src/components/UI/FileUploadButton.js b/packages/netlify-cms-core/src/components/UI/FileUploadButton.js index 4df00867..61bf36c7 100644 --- a/packages/netlify-cms-core/src/components/UI/FileUploadButton.js +++ b/packages/netlify-cms-core/src/components/UI/FileUploadButton.js @@ -1,17 +1,19 @@ import React from 'react'; import PropTypes from 'prop-types'; -export const FileUploadButton = ({ label, imagesOnly, onChange, disabled, className }) => ( - -); +export function FileUploadButton({ label, imagesOnly, onChange, disabled, className }) { + return ( + + ); +} FileUploadButton.propTypes = { className: PropTypes.string, diff --git a/packages/netlify-cms-core/src/components/UI/Modal.js b/packages/netlify-cms-core/src/components/UI/Modal.js index 3c8e1c98..6e0f2301 100644 --- a/packages/netlify-cms-core/src/components/UI/Modal.js +++ b/packages/netlify-cms-core/src/components/UI/Modal.js @@ -4,15 +4,17 @@ import { css, Global, ClassNames } from '@emotion/core'; import ReactModal from 'react-modal'; import { transitions, shadows, lengths, zIndex } from 'netlify-cms-ui-default'; -const ReactModalGlobalStyles = () => ( - -); +function ReactModalGlobalStyles() { + return ( + + ); +} const styleStrings = { modalBody: ` diff --git a/packages/netlify-cms-core/src/components/UI/SettingsDropdown.js b/packages/netlify-cms-core/src/components/UI/SettingsDropdown.js index cce85908..31cd830b 100644 --- a/packages/netlify-cms-core/src/components/UI/SettingsDropdown.js +++ b/packages/netlify-cms-core/src/components/UI/SettingsDropdown.js @@ -46,43 +46,50 @@ const AppHeaderTestRepoIndicator = styled.a` padding: 10px 16px; `; -const Avatar = ({ imageUrl }) => - imageUrl ? : ; +function Avatar({ imageUrl }) { + return imageUrl ? ( + + ) : ( + + ); +} Avatar.propTypes = { imageUrl: PropTypes.string, }; -const SettingsDropdown = ({ displayUrl, isTestRepo, imageUrl, onLogoutClick, t }) => ( - - {isTestRepo && ( - - Test Backend ↗ - - )} - {displayUrl ? ( - - {stripProtocol(displayUrl)} - - ) : null} - ( - - - +function SettingsDropdown({ displayUrl, isTestRepo, imageUrl, onLogoutClick, t }) { + return ( + + {isTestRepo && ( + + Test Backend ↗ + )} - > - - - -); + {displayUrl ? ( + + {stripProtocol(displayUrl)} + + ) : null} + ( + + + + )} + > + + + + ); +} SettingsDropdown.propTypes = { displayUrl: PropTypes.string, diff --git a/packages/netlify-cms-core/src/components/UI/Toast.js b/packages/netlify-cms-core/src/components/UI/Toast.js index 97b4666b..44c7bf29 100644 --- a/packages/netlify-cms-core/src/components/UI/Toast.js +++ b/packages/netlify-cms-core/src/components/UI/Toast.js @@ -6,18 +6,20 @@ import { translate } from 'react-polyglot'; import reduxNotificationsStyles from 'redux-notifications/lib/styles.css'; import { shadows, colors, lengths, zIndex } from 'netlify-cms-ui-default'; -const ReduxNotificationsGlobalStyles = () => ( - -); + .notif__container { + z-index: ${zIndex.zIndex10000}; + white-space: pre-wrap; + } + `} + /> + ); +} const styles = { toast: css` @@ -47,12 +49,14 @@ const styles = { `, }; -const Toast = ({ kind, message, t }) => ( -
- - {t(message.key, { details: message.details })} -
-); +function Toast({ kind, message, t }) { + return ( +
+ + {t(message.key, { details: message.details })} +
+ ); +} Toast.propTypes = { kind: PropTypes.oneOf(['info', 'success', 'warning', 'danger']).isRequired, diff --git a/packages/netlify-cms-core/src/components/UI/__tests__/ErrorBoundary.spec.js b/packages/netlify-cms-core/src/components/UI/__tests__/ErrorBoundary.spec.js index 0502330e..c4c05aa8 100644 --- a/packages/netlify-cms-core/src/components/UI/__tests__/ErrorBoundary.spec.js +++ b/packages/netlify-cms-core/src/components/UI/__tests__/ErrorBoundary.spec.js @@ -4,9 +4,9 @@ import { render } from '@testing-library/react'; import { fromJS } from 'immutable'; import { oneLineTrim } from 'common-tags'; -const WithError = () => { +function WithError() { throw new Error('Some unknown error'); -}; +} jest.spyOn(console, 'error').mockImplementation(() => ({})); diff --git a/packages/netlify-cms-core/src/components/Workflow/WorkflowCard.js b/packages/netlify-cms-core/src/components/Workflow/WorkflowCard.js index b9db491e..8e9f7839 100644 --- a/packages/netlify-cms-core/src/components/Workflow/WorkflowCard.js +++ b/packages/netlify-cms-core/src/components/Workflow/WorkflowCard.js @@ -98,7 +98,7 @@ const WorkflowCardContainer = styled.div` } `; -const lastChangePhraseKey = (date, author) => { +function lastChangePhraseKey(date, author) { if (date && author) { return 'lastChange'; } else if (date) { @@ -106,7 +106,7 @@ const lastChangePhraseKey = (date, author) => { } else if (author) { return 'lastChangeNoDate'; } -}; +} const CardDate = translate()(({ t, date, author }) => { const key = lastChangePhraseKey(date, author); @@ -117,7 +117,7 @@ const CardDate = translate()(({ t, date, author }) => { } }); -const WorkflowCard = ({ +function WorkflowCard({ collectionLabel, title, authorLastChange, @@ -130,30 +130,32 @@ const WorkflowCard = ({ canPublish, onPublish, t, -}) => ( - - - {collectionLabel} - {title} - {(timestamp || authorLastChange) && } - {body} - - - - {isModification - ? t('workflow.workflowCard.deleteChanges') - : t('workflow.workflowCard.deleteNewEntry')} - - {allowPublish && ( - +}) { + return ( + + + {collectionLabel} + {title} + {(timestamp || authorLastChange) && } + {body} + + + {isModification - ? t('workflow.workflowCard.publishChanges') - : t('workflow.workflowCard.publishNewEntry')} - - )} - - -); + ? t('workflow.workflowCard.deleteChanges') + : t('workflow.workflowCard.deleteNewEntry')} + + {allowPublish && ( + + {isModification + ? t('workflow.workflowCard.publishChanges') + : t('workflow.workflowCard.publishNewEntry')} + + )} + + + ); +} WorkflowCard.propTypes = { collectionLabel: PropTypes.string.isRequired, diff --git a/packages/netlify-cms-core/src/components/Workflow/WorkflowList.js b/packages/netlify-cms-core/src/components/Workflow/WorkflowList.js index 64992637..ecd96987 100644 --- a/packages/netlify-cms-core/src/components/Workflow/WorkflowList.js +++ b/packages/netlify-cms-core/src/components/Workflow/WorkflowList.js @@ -116,7 +116,7 @@ const ColumnCount = styled.p` // This is a namespace so that we can only drop these elements on a DropTarget with the same const DNDNamespace = 'cms-workflow'; -const getColumnHeaderText = (columnName, t) => { +function getColumnHeaderText(columnName, t) { switch (columnName) { case 'draft': return t('workflow.workflowList.draftHeader'); @@ -125,7 +125,7 @@ const getColumnHeaderText = (columnName, t) => { case 'pending_publish': return t('workflow.workflowList.readyHeader'); } -}; +} class WorkflowList extends React.Component { static propTypes = { diff --git a/packages/netlify-cms-core/src/constants/configSchema.js b/packages/netlify-cms-core/src/constants/configSchema.js index f193a4c0..945d01ae 100644 --- a/packages/netlify-cms-core/src/constants/configSchema.js +++ b/packages/netlify-cms-core/src/constants/configSchema.js @@ -43,7 +43,7 @@ const i18nField = { /** * Config for fields in both file and folder collections. */ -const fieldsConfig = () => { +function fieldsConfig() { const id = uuid(); return { $id: `fields_${id}`, @@ -77,7 +77,7 @@ const fieldsConfig = () => { }, uniqueItemProperties: ['name'], }; -}; +} const viewFilters = { type: 'array', @@ -121,201 +121,203 @@ const viewGroups = { * fix a circular dependency problem for WebPack, * where the imports get resolved asynchronously. */ -const getConfigSchema = () => ({ - type: 'object', - properties: { - backend: { - type: 'object', - properties: { - name: { type: 'string', examples: ['test-repo'] }, - auth_scope: { - type: 'string', - examples: ['repo', 'public_repo'], - enum: ['repo', 'public_repo'], - }, - cms_label_prefix: { type: 'string', minLength: 1 }, - open_authoring: { type: 'boolean', examples: [true] }, - }, - required: ['name'], - }, - local_backend: { - oneOf: [ - { type: 'boolean' }, - { - type: 'object', - properties: { - url: { type: 'string', examples: ['http://localhost:8081/api/v1'] }, - allowed_hosts: { - type: 'array', - items: { type: 'string' }, - }, - }, - additionalProperties: false, - }, - ], - }, - locale: { type: 'string', examples: ['en', 'fr', 'de'] }, - i18n: i18nRoot, - site_url: { type: 'string', examples: ['https://example.com'] }, - display_url: { type: 'string', examples: ['https://example.com'] }, - logo_url: { type: 'string', examples: ['https://example.com/images/logo.svg'] }, - show_preview_links: { type: 'boolean' }, - media_folder: { type: 'string', examples: ['assets/uploads'] }, - public_folder: { type: 'string', examples: ['/uploads'] }, - media_folder_relative: { type: 'boolean' }, - media_library: { - type: 'object', - properties: { - name: { type: 'string', examples: ['uploadcare'] }, - config: { type: 'object' }, - }, - required: ['name'], - }, - publish_mode: { - type: 'string', - enum: ['simple', 'editorial_workflow'], - examples: ['editorial_workflow'], - }, - slug: { - type: 'object', - properties: { - encoding: { type: 'string', enum: ['unicode', 'ascii'] }, - clean_accents: { type: 'boolean' }, - }, - }, - collections: { - type: 'array', - minItems: 1, - items: { - // ------- Each collection: ------- +function getConfigSchema() { + return { + type: 'object', + properties: { + backend: { type: 'object', properties: { - name: { type: 'string' }, - label: { type: 'string' }, - label_singular: { type: 'string' }, - description: { type: 'string' }, - folder: { type: 'string' }, - files: { - type: 'array', - items: { - // ------- Each file: ------- - type: 'object', - properties: { - name: { type: 'string' }, - label: { type: 'string' }, - label_singular: { type: 'string' }, - description: { type: 'string' }, - file: { type: 'string' }, - preview_path: { type: 'string' }, - preview_path_date_field: { type: 'string' }, - fields: fieldsConfig(), - }, - required: ['name', 'label', 'file', 'fields'], - }, - uniqueItemProperties: ['name'], + name: { type: 'string', examples: ['test-repo'] }, + auth_scope: { + type: 'string', + examples: ['repo', 'public_repo'], + enum: ['repo', 'public_repo'], }, - identifier_field: { type: 'string' }, - summary: { type: 'string' }, - slug: { type: 'string' }, - path: { type: 'string' }, - preview_path: { type: 'string' }, - preview_path_date_field: { type: 'string' }, - create: { type: 'boolean' }, - publish: { type: 'boolean' }, - hide: { type: 'boolean' }, - editor: { + cms_label_prefix: { type: 'string', minLength: 1 }, + open_authoring: { type: 'boolean', examples: [true] }, + }, + required: ['name'], + }, + local_backend: { + oneOf: [ + { type: 'boolean' }, + { type: 'object', properties: { - preview: { type: 'boolean' }, - }, - }, - format: { type: 'string', enum: Object.keys(formatExtensions) }, - extension: { type: 'string' }, - frontmatter_delimiter: { - type: ['string', 'array'], - minItems: 2, - maxItems: 2, - items: { - type: 'string', - }, - }, - fields: fieldsConfig(), - sortable_fields: { - type: 'array', - items: { - type: 'string', - }, - }, - sortableFields: { - type: 'array', - items: { - type: 'string', - }, - }, - view_filters: viewFilters, - view_groups: viewGroups, - nested: { - type: 'object', - properties: { - depth: { type: 'number', minimum: 1, maximum: 1000 }, - summary: { type: 'string' }, - }, - required: ['depth'], - }, - meta: { - type: 'object', - properties: { - path: { - type: 'object', - properties: { - label: { type: 'string' }, - widget: { type: 'string' }, - index_file: { type: 'string' }, - }, - required: ['label', 'widget', 'index_file'], + url: { type: 'string', examples: ['http://localhost:8081/api/v1'] }, + allowed_hosts: { + type: 'array', + items: { type: 'string' }, }, }, additionalProperties: false, - minProperties: 1, }, - i18n: i18nCollection, + ], + }, + locale: { type: 'string', examples: ['en', 'fr', 'de'] }, + i18n: i18nRoot, + site_url: { type: 'string', examples: ['https://example.com'] }, + display_url: { type: 'string', examples: ['https://example.com'] }, + logo_url: { type: 'string', examples: ['https://example.com/images/logo.svg'] }, + show_preview_links: { type: 'boolean' }, + media_folder: { type: 'string', examples: ['assets/uploads'] }, + public_folder: { type: 'string', examples: ['/uploads'] }, + media_folder_relative: { type: 'boolean' }, + media_library: { + type: 'object', + properties: { + name: { type: 'string', examples: ['uploadcare'] }, + config: { type: 'object' }, }, - required: ['name', 'label'], - oneOf: [{ required: ['files'] }, { required: ['folder', 'fields'] }], - not: { - required: ['sortable_fields', 'sortableFields'], - }, - if: { required: ['extension'] }, - then: { - // Cannot infer format from extension. - if: { - properties: { - extension: { enum: Object.keys(extensionFormatters) }, - }, - }, - else: { required: ['format'] }, - }, - dependencies: { - frontmatter_delimiter: { - properties: { - format: { enum: frontmatterFormats }, - }, - required: ['format'], - }, + required: ['name'], + }, + publish_mode: { + type: 'string', + enum: ['simple', 'editorial_workflow'], + examples: ['editorial_workflow'], + }, + slug: { + type: 'object', + properties: { + encoding: { type: 'string', enum: ['unicode', 'ascii'] }, + clean_accents: { type: 'boolean' }, }, }, - uniqueItemProperties: ['name'], - }, - editor: { - type: 'object', - properties: { - preview: { type: 'boolean' }, + collections: { + type: 'array', + minItems: 1, + items: { + // ------- Each collection: ------- + type: 'object', + properties: { + name: { type: 'string' }, + label: { type: 'string' }, + label_singular: { type: 'string' }, + description: { type: 'string' }, + folder: { type: 'string' }, + files: { + type: 'array', + items: { + // ------- Each file: ------- + type: 'object', + properties: { + name: { type: 'string' }, + label: { type: 'string' }, + label_singular: { type: 'string' }, + description: { type: 'string' }, + file: { type: 'string' }, + preview_path: { type: 'string' }, + preview_path_date_field: { type: 'string' }, + fields: fieldsConfig(), + }, + required: ['name', 'label', 'file', 'fields'], + }, + uniqueItemProperties: ['name'], + }, + identifier_field: { type: 'string' }, + summary: { type: 'string' }, + slug: { type: 'string' }, + path: { type: 'string' }, + preview_path: { type: 'string' }, + preview_path_date_field: { type: 'string' }, + create: { type: 'boolean' }, + publish: { type: 'boolean' }, + hide: { type: 'boolean' }, + editor: { + type: 'object', + properties: { + preview: { type: 'boolean' }, + }, + }, + format: { type: 'string', enum: Object.keys(formatExtensions) }, + extension: { type: 'string' }, + frontmatter_delimiter: { + type: ['string', 'array'], + minItems: 2, + maxItems: 2, + items: { + type: 'string', + }, + }, + fields: fieldsConfig(), + sortable_fields: { + type: 'array', + items: { + type: 'string', + }, + }, + sortableFields: { + type: 'array', + items: { + type: 'string', + }, + }, + view_filters: viewFilters, + view_groups: viewGroups, + nested: { + type: 'object', + properties: { + depth: { type: 'number', minimum: 1, maximum: 1000 }, + summary: { type: 'string' }, + }, + required: ['depth'], + }, + meta: { + type: 'object', + properties: { + path: { + type: 'object', + properties: { + label: { type: 'string' }, + widget: { type: 'string' }, + index_file: { type: 'string' }, + }, + required: ['label', 'widget', 'index_file'], + }, + }, + additionalProperties: false, + minProperties: 1, + }, + i18n: i18nCollection, + }, + required: ['name', 'label'], + oneOf: [{ required: ['files'] }, { required: ['folder', 'fields'] }], + not: { + required: ['sortable_fields', 'sortableFields'], + }, + if: { required: ['extension'] }, + then: { + // Cannot infer format from extension. + if: { + properties: { + extension: { enum: Object.keys(extensionFormatters) }, + }, + }, + else: { required: ['format'] }, + }, + dependencies: { + frontmatter_delimiter: { + properties: { + format: { enum: frontmatterFormats }, + }, + required: ['format'], + }, + }, + }, + uniqueItemProperties: ['name'], + }, + editor: { + type: 'object', + properties: { + preview: { type: 'boolean' }, + }, }, }, - }, - required: ['backend', 'collections'], - anyOf: [{ required: ['media_folder'] }, { required: ['media_library'] }], -}); + required: ['backend', 'collections'], + anyOf: [{ required: ['media_folder'] }, { required: ['media_library'] }], + }; +} function getWidgetSchemas() { const schemas = getWidgets().map(widget => ({ [widget.name]: widget.schema })); diff --git a/packages/netlify-cms-core/src/formats/formats.js b/packages/netlify-cms-core/src/formats/formats.js index fdb5d748..00b4aba6 100644 --- a/packages/netlify-cms-core/src/formats/formats.js +++ b/packages/netlify-cms-core/src/formats/formats.js @@ -28,8 +28,8 @@ export const extensionFormatters = { html: FrontmatterInfer, }; -const formatByName = (name, customDelimiter) => - ({ +function formatByName(name, customDelimiter) { + return { yml: yamlFormatter, yaml: yamlFormatter, toml: tomlFormatter, @@ -38,7 +38,8 @@ const formatByName = (name, customDelimiter) => 'json-frontmatter': frontmatterJSON(customDelimiter), 'toml-frontmatter': frontmatterTOML(customDelimiter), 'yaml-frontmatter': frontmatterYAML(customDelimiter), - }[name]); + }[name]; +} export function resolveFormat(collection, entry) { // Check for custom delimiter diff --git a/packages/netlify-cms-core/src/formats/frontmatter.js b/packages/netlify-cms-core/src/formats/frontmatter.js index e120bfa7..539857bc 100644 --- a/packages/netlify-cms-core/src/formats/frontmatter.js +++ b/packages/netlify-cms-core/src/formats/frontmatter.js @@ -51,12 +51,13 @@ function inferFrontmatterFormat(str) { } } -export const getFormatOpts = format => - ({ +export function getFormatOpts(format) { + return { yaml: { language: 'yaml', delimiters: '---' }, toml: { language: 'toml', delimiters: '+++' }, json: { language: 'json', delimiters: ['{', '}'] }, - }[format]); + }[format]; +} class FrontmatterFormatter { constructor(format, customDelimiter) { @@ -99,6 +100,15 @@ class FrontmatterFormatter { } export const FrontmatterInfer = new FrontmatterFormatter(); -export const frontmatterYAML = customDelimiter => new FrontmatterFormatter('yaml', customDelimiter); -export const frontmatterTOML = customDelimiter => new FrontmatterFormatter('toml', customDelimiter); -export const frontmatterJSON = customDelimiter => new FrontmatterFormatter('json', customDelimiter); + +export function frontmatterYAML(customDelimiter) { + return new FrontmatterFormatter('yaml', customDelimiter); +} + +export function frontmatterTOML(customDelimiter) { + return new FrontmatterFormatter('toml', customDelimiter); +} + +export function frontmatterJSON(customDelimiter) { + return new FrontmatterFormatter('json', customDelimiter); +} diff --git a/packages/netlify-cms-core/src/formats/helpers.js b/packages/netlify-cms-core/src/formats/helpers.js index a4ac9261..3b1620ad 100644 --- a/packages/netlify-cms-core/src/formats/helpers.js +++ b/packages/netlify-cms-core/src/formats/helpers.js @@ -1,8 +1,10 @@ -export const sortKeys = (sortedKeys = [], selector = a => a) => (a, b) => { - const idxA = sortedKeys.indexOf(selector(a)); - const idxB = sortedKeys.indexOf(selector(b)); - if (idxA === -1 || idxB === -1) return 0; - if (idxA > idxB) return 1; - if (idxA < idxB) return -1; - return 0; -}; +export function sortKeys(sortedKeys = [], selector = a => a) { + return (a, b) => { + const idxA = sortedKeys.indexOf(selector(a)); + const idxB = sortedKeys.indexOf(selector(b)); + if (idxA === -1 || idxB === -1) return 0; + if (idxA > idxB) return 1; + if (idxA < idxB) return -1; + return 0; + }; +} diff --git a/packages/netlify-cms-core/src/formats/toml.js b/packages/netlify-cms-core/src/formats/toml.js index 9a228f14..8b435837 100644 --- a/packages/netlify-cms-core/src/formats/toml.js +++ b/packages/netlify-cms-core/src/formats/toml.js @@ -4,7 +4,7 @@ import moment from 'moment'; import AssetProxy from 'ValueObjects/AssetProxy'; import { sortKeys } from './helpers'; -const outputReplacer = (key, value) => { +function outputReplacer(key, value) { if (moment.isMoment(value)) { return value.format(value._f); } @@ -17,7 +17,7 @@ const outputReplacer = (key, value) => { } // Return `false` to use default (`undefined` would delete key). return false; -}; +} export default { fromFile(content) { diff --git a/packages/netlify-cms-core/src/formats/yaml.js b/packages/netlify-cms-core/src/formats/yaml.js index d4ed37d3..7d592680 100644 --- a/packages/netlify-cms-core/src/formats/yaml.js +++ b/packages/netlify-cms-core/src/formats/yaml.js @@ -1,7 +1,7 @@ import yaml from 'yaml'; import { sortKeys } from './helpers'; -const addComments = (items, comments, prefix = '') => { +function addComments(items, comments, prefix = '') { items.forEach(item => { if (item.key !== undefined) { const itemKey = item.key.toString(); @@ -15,7 +15,7 @@ const addComments = (items, comments, prefix = '') => { } } }); -}; +} const timestampTag = { identify: value => value instanceof Date, diff --git a/packages/netlify-cms-core/src/lib/formatters.ts b/packages/netlify-cms-core/src/lib/formatters.ts index 3859847a..46dcfdf8 100644 --- a/packages/netlify-cms-core/src/lib/formatters.ts +++ b/packages/netlify-cms-core/src/lib/formatters.ts @@ -41,12 +41,12 @@ type Options = { authorName?: string; }; -export const commitMessageFormatter = ( +export function commitMessageFormatter( type: string, config: Config, { slug, path, collection, authorLogin, authorName }: Options, isOpenAuthoring?: boolean, -) => { +) { const templates = commitMessageTemplates.merge( config.getIn(['backend', 'commit_messages'], Map()), ); @@ -88,9 +88,9 @@ export const commitMessageFormatter = ( }); return message; -}; +} -export const prepareSlug = (slug: string) => { +export function prepareSlug(slug: string) { return ( slug .trim() @@ -103,20 +103,20 @@ export const prepareSlug = (slug: string) => { // Replace periods with dashes. .replace(/[.]/g, '-') ); -}; +} -export const getProcessSegment = (slugConfig: SlugConfig, ignoreValues: string[] = []) => { +export function getProcessSegment(slugConfig: SlugConfig, ignoreValues: string[] = []) { return (value: string) => ignoreValues.includes(value) ? value : flow([value => String(value), prepareSlug, partialRight(sanitizeSlug, slugConfig)])(value); -}; +} -export const slugFormatter = ( +export function slugFormatter( collection: Collection, entryData: Map, slugConfig: SlugConfig, -) => { +) { const slugTemplate = collection.get('slug') || '{{slug}}'; const identifier = entryData.getIn(keyToPathArray(selectIdentifier(collection) as string)); @@ -138,15 +138,15 @@ export const slugFormatter = ( value === slug ? value : processSegment(value), ); } -}; +} -export const previewUrlFormatter = ( +export function previewUrlFormatter( baseUrl: string, collection: Collection, slug: string, slugConfig: SlugConfig, entry: EntryMap, -) => { +) { /** * Preview URL can't be created without `baseUrl`. This makes preview URLs * optional for backends that don't support them. @@ -160,12 +160,13 @@ export const previewUrlFormatter = ( const isFileCollection = collection.get('type') === FILES; const file = isFileCollection ? getFileFromSlug(collection, entry.get('slug')) : undefined; - const getPathTemplate = () => { + function getPathTemplate() { return file?.get('preview_path') ?? collection.get('preview_path'); - }; - const getDateField = () => { + } + + function getDateField() { return file?.get('preview_path_date_field') ?? collection.get('preview_path_date_field'); - }; + } /** * If a `previewPath` is provided for the collection/file, use it to construct the @@ -209,13 +210,9 @@ export const previewUrlFormatter = ( const previewPath = trimStart(compiledPath, ' /'); return `${basePath}/${previewPath}`; -}; +} -export const summaryFormatter = ( - summaryTemplate: string, - entry: EntryMap, - collection: Collection, -) => { +export function summaryFormatter(summaryTemplate: string, entry: EntryMap, collection: Collection) { let entryData = entry.get('data'); const date = parseDateFromEntry( @@ -234,16 +231,16 @@ export const summaryFormatter = ( } const summary = compileStringTemplate(summaryTemplate, date, identifier, entryData); return summary; -}; +} -export const folderFormatter = ( +export function folderFormatter( folderTemplate: string, entry: EntryMap | undefined, collection: Collection, defaultFolder: string, folderKey: string, slugConfig: SlugConfig, -) => { +) { if (!entry || !entry.get('data')) { return folderTemplate; } @@ -268,4 +265,4 @@ export const folderFormatter = ( ); return mediaFolder; -}; +} diff --git a/packages/netlify-cms-core/src/lib/i18n.ts b/packages/netlify-cms-core/src/lib/i18n.ts index accc0d1f..ed2086c0 100644 --- a/packages/netlify-cms-core/src/lib/i18n.ts +++ b/packages/netlify-cms-core/src/lib/i18n.ts @@ -18,9 +18,9 @@ export enum I18N_FIELD { NONE = 'none', } -export const hasI18n = (collection: Collection) => { +export function hasI18n(collection: Collection) { return collection.has(I18N); -}; +} type I18nInfo = { locales: string[]; @@ -28,53 +28,53 @@ type I18nInfo = { structure: I18N_STRUCTURE; }; -export const getI18nInfo = (collection: Collection) => { +export function getI18nInfo(collection: Collection) { if (!hasI18n(collection)) { return {}; } const { structure, locales, default_locale: defaultLocale } = collection.get(I18N).toJS(); return { structure, locales, defaultLocale } as I18nInfo; -}; +} -export const getI18nFilesDepth = (collection: Collection, depth: number) => { +export function getI18nFilesDepth(collection: Collection, depth: number) { const { structure } = getI18nInfo(collection) as I18nInfo; if (structure === I18N_STRUCTURE.MULTIPLE_FOLDERS) { return depth + 1; } return depth; -}; +} -export const isFieldTranslatable = (field: EntryField, locale: string, defaultLocale: string) => { +export function isFieldTranslatable(field: EntryField, locale: string, defaultLocale: string) { const isTranslatable = locale !== defaultLocale && field.get(I18N) === I18N_FIELD.TRANSLATE; return isTranslatable; -}; +} -export const isFieldDuplicate = (field: EntryField, locale: string, defaultLocale: string) => { +export function isFieldDuplicate(field: EntryField, locale: string, defaultLocale: string) { const isDuplicate = locale !== defaultLocale && field.get(I18N) === I18N_FIELD.DUPLICATE; return isDuplicate; -}; +} -export const isFieldHidden = (field: EntryField, locale: string, defaultLocale: string) => { +export function isFieldHidden(field: EntryField, locale: string, defaultLocale: string) { const isHidden = locale !== defaultLocale && field.get(I18N) === I18N_FIELD.NONE; return isHidden; -}; +} -export const getLocaleDataPath = (locale: string) => { +export function getLocaleDataPath(locale: string) { return [I18N, locale, 'data']; -}; +} -export const getDataPath = (locale: string, defaultLocale: string) => { +export function getDataPath(locale: string, defaultLocale: string) { const dataPath = locale !== defaultLocale ? getLocaleDataPath(locale) : ['data']; return dataPath; -}; +} -export const getFilePath = ( +export function getFilePath( structure: I18N_STRUCTURE, extension: string, path: string, slug: string, locale: string, -) => { +) { switch (structure) { case I18N_STRUCTURE.MULTIPLE_FOLDERS: return path.replace(`/${slug}`, `/${locale}/${slug}`); @@ -84,9 +84,9 @@ export const getFilePath = ( default: return path; } -}; +} -export const getLocaleFromPath = (structure: I18N_STRUCTURE, extension: string, path: string) => { +export function getLocaleFromPath(structure: I18N_STRUCTURE, extension: string, path: string) { switch (structure) { case I18N_STRUCTURE.MULTIPLE_FOLDERS: { const parts = path.split('/'); @@ -103,23 +103,23 @@ export const getLocaleFromPath = (structure: I18N_STRUCTURE, extension: string, default: return ''; } -}; +} -export const getFilePaths = ( +export function getFilePaths( collection: Collection, extension: string, path: string, slug: string, -) => { +) { const { structure, locales } = getI18nInfo(collection) as I18nInfo; const paths = locales.map(locale => getFilePath(structure as I18N_STRUCTURE, extension, path, slug, locale), ); return paths; -}; +} -export const normalizeFilePath = (structure: I18N_STRUCTURE, path: string, locale: string) => { +export function normalizeFilePath(structure: I18N_STRUCTURE, path: string, locale: string) { switch (structure) { case I18N_STRUCTURE.MULTIPLE_FOLDERS: return path.replace(`${locale}/`, ''); @@ -129,9 +129,9 @@ export const normalizeFilePath = (structure: I18N_STRUCTURE, path: string, local default: return path; } -}; +} -export const getI18nFiles = ( +export function getI18nFiles( collection: Collection, extension: string, entryDraft: EntryMap, @@ -139,7 +139,7 @@ export const getI18nFiles = ( path: string, slug: string, newPath?: string, -) => { +) { const { structure, defaultLocale, locales } = getI18nInfo(collection) as I18nInfo; if (structure === I18N_STRUCTURE.SINGLE_FILE) { @@ -176,13 +176,13 @@ export const getI18nFiles = ( }) .filter(dataFile => dataFile.raw); return dataFiles; -}; +} -export const getI18nBackup = ( +export function getI18nBackup( collection: Collection, entry: EntryMap, entryToRaw: (entry: EntryMap) => string, -) => { +) { const { locales, defaultLocale } = getI18nInfo(collection) as I18nInfo; const i18nBackup = locales @@ -198,26 +198,26 @@ export const getI18nBackup = ( }, {} as Record); return i18nBackup; -}; +} -export const formatI18nBackup = ( +export function formatI18nBackup( i18nBackup: Record, formatRawData: (raw: string) => EntryValue, -) => { +) { const i18n = Object.entries(i18nBackup).reduce((acc, [locale, { raw }]) => { const entry = formatRawData(raw); return { ...acc, [locale]: { data: entry.data } }; }, {}); return i18n; -}; +} -const mergeValues = ( +function mergeValues( collection: Collection, structure: I18N_STRUCTURE, defaultLocale: string, values: { locale: string; value: EntryValue }[], -) => { +) { let defaultEntry = values.find(e => e.locale === defaultLocale); if (!defaultEntry) { defaultEntry = values[0]; @@ -241,9 +241,9 @@ const mergeValues = ( }; return entryValue; -}; +} -const mergeSingleFileValue = (entryValue: EntryValue, defaultLocale: string, locales: string[]) => { +function mergeSingleFileValue(entryValue: EntryValue, defaultLocale: string, locales: string[]) { const data = entryValue.data[defaultLocale] || {}; const i18n = locales .filter(l => l !== defaultLocale) @@ -259,15 +259,15 @@ const mergeSingleFileValue = (entryValue: EntryValue, defaultLocale: string, loc i18n, raw: '', }; -}; +} -export const getI18nEntry = async ( +export async function getI18nEntry( collection: Collection, extension: string, path: string, slug: string, getEntryValue: (path: string) => Promise, -) => { +) { const { structure, locales, defaultLocale } = getI18nInfo(collection) as I18nInfo; let entryValue: EntryValue; @@ -291,9 +291,9 @@ export const getI18nEntry = async ( } return entryValue; -}; +} -export const groupEntries = (collection: Collection, extension: string, entries: EntryValue[]) => { +export function groupEntries(collection: Collection, extension: string, entries: EntryValue[]) { const { structure, defaultLocale, locales } = getI18nInfo(collection) as I18nInfo; if (structure === I18N_STRUCTURE.SINGLE_FILE) { return entries.map(e => mergeSingleFileValue(e, defaultLocale, locales)); @@ -315,15 +315,15 @@ export const groupEntries = (collection: Collection, extension: string, entries: }, [] as EntryValue[]); return groupedEntries; -}; +} -export const getI18nDataFiles = ( +export function getI18nDataFiles( collection: Collection, extension: string, path: string, slug: string, diffFiles: { path: string; id: string; newFile: boolean }[], -) => { +) { const { structure } = getI18nInfo(collection) as I18nInfo; if (structure === I18N_STRUCTURE.SINGLE_FILE) { return diffFiles; @@ -339,10 +339,10 @@ export const getI18nDataFiles = ( }, [] as { path: string; id: string; newFile: boolean }[]); return dataFiles; -}; +} // eslint-disable-next-line @typescript-eslint/no-explicit-any -export const duplicateDefaultI18nFields = (collection: Collection, dataFields: any) => { +export function duplicateDefaultI18nFields(collection: Collection, dataFields: any) { const { locales, defaultLocale } = getI18nInfo(collection) as I18nInfo; const i18nFields = Object.fromEntries( @@ -352,15 +352,15 @@ export const duplicateDefaultI18nFields = (collection: Collection, dataFields: a ); return i18nFields; -}; +} -export const duplicateI18nFields = ( +export function duplicateI18nFields( entryDraft: EntryDraft, field: EntryField, locales: string[], defaultLocale: string, fieldPath: string[] = [field.get('name')], -) => { +) { const value = entryDraft.getIn(['entry', 'data', ...fieldPath]); if (field.get(I18N) === I18N_FIELD.DUPLICATE) { locales @@ -392,21 +392,21 @@ export const duplicateI18nFields = ( } return entryDraft; -}; +} -export const getPreviewEntry = (entry: EntryMap, locale: string, defaultLocale: string) => { +export function getPreviewEntry(entry: EntryMap, locale: string, defaultLocale: string) { if (locale === defaultLocale) { return entry; } return entry.set('data', entry.getIn([I18N, locale, 'data'])); -}; +} -export const serializeI18n = ( +export function serializeI18n( collection: Collection, entry: Entry, // eslint-disable-next-line @typescript-eslint/no-explicit-any serializeValues: (data: any) => any, -) => { +) { const { locales, defaultLocale } = getI18nInfo(collection) as I18nInfo; locales @@ -417,4 +417,4 @@ export const serializeI18n = ( }); return entry; -}; +} diff --git a/packages/netlify-cms-core/src/lib/serializeEntryValues.js b/packages/netlify-cms-core/src/lib/serializeEntryValues.js index 9f13c46d..e7fd4248 100644 --- a/packages/netlify-cms-core/src/lib/serializeEntryValues.js +++ b/packages/netlify-cms-core/src/lib/serializeEntryValues.js @@ -20,7 +20,7 @@ import { getWidgetValueSerializer } from './registry'; * registered deserialization handlers run on entry load, and serialization * handlers run on persist. */ -const runSerializer = (values, fields, method) => { +function runSerializer(values, fields, method) { /** * Reduce the list of fields to a map where keys are field names and values * are field values, serializing the values of fields whose widgets have @@ -63,12 +63,12 @@ const runSerializer = (values, fields, method) => { serializedData = values.mergeDeep(serializedData); return serializedData; -}; +} -export const serializeValues = (values, fields) => { +export function serializeValues(values, fields) { return runSerializer(values, fields, 'serialize'); -}; +} -export const deserializeValues = (values, fields) => { +export function deserializeValues(values, fields) { return runSerializer(values, fields, 'deserialize'); -}; +} diff --git a/packages/netlify-cms-core/src/lib/urlHelper.ts b/packages/netlify-cms-core/src/lib/urlHelper.ts index 9137a964..4f369ec4 100644 --- a/packages/netlify-cms-core/src/lib/urlHelper.ts +++ b/packages/netlify-cms-core/src/lib/urlHelper.ts @@ -36,8 +36,14 @@ export function stripProtocol(urlString: string) { */ const uriChars = /[\w\-.~]/i; const ucsChars = /[\xA0-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}\u{10000}-\u{1FFFD}\u{20000}-\u{2FFFD}\u{30000}-\u{3FFFD}\u{40000}-\u{4FFFD}\u{50000}-\u{5FFFD}\u{60000}-\u{6FFFD}\u{70000}-\u{7FFFD}\u{80000}-\u{8FFFD}\u{90000}-\u{9FFFD}\u{A0000}-\u{AFFFD}\u{B0000}-\u{BFFFD}\u{C0000}-\u{CFFFD}\u{D0000}-\u{DFFFD}\u{E1000}-\u{EFFFD}]/u; -const validURIChar = (char: string) => uriChars.test(char); -const validIRIChar = (char: string) => uriChars.test(char) || ucsChars.test(char); + +function validURIChar(char: string) { + return uriChars.test(char); +} + +function validIRIChar(char: string) { + return uriChars.test(char) || ucsChars.test(char); +} export function getCharReplacer(encoding: string, replacement: string) { let validChar: (char: string) => boolean; diff --git a/packages/netlify-cms-core/src/mediaLibrary.ts b/packages/netlify-cms-core/src/mediaLibrary.ts index 1b321085..940492fe 100644 --- a/packages/netlify-cms-core/src/mediaLibrary.ts +++ b/packages/netlify-cms-core/src/mediaLibrary.ts @@ -18,6 +18,12 @@ interface MediaLibrary { }) => MediaLibraryInstance; } +function handleInsert(url: string) { + // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // @ts-ignore + return store.dispatch(insertMedia(url, undefined)); +} + const initializeMediaLibrary = once(async function initializeMediaLibrary(name, options) { const lib = (getMediaLibrary(name) as unknown) as MediaLibrary | undefined; if (!lib) { @@ -26,9 +32,6 @@ const initializeMediaLibrary = once(async function initializeMediaLibrary(name, ); store.dispatch(configFailed(err)); } else { - // eslint-disable-next-line @typescript-eslint/ban-ts-ignore - // @ts-ignore - const handleInsert = (url: string) => store.dispatch(insertMedia(url, undefined)); const instance = await lib.init({ options, handleInsert }); store.dispatch(createMediaLibrary(instance)); } diff --git a/packages/netlify-cms-core/src/reducers/__tests__/collections.spec.js b/packages/netlify-cms-core/src/reducers/__tests__/collections.spec.js index eb232d5b..ec776f49 100644 --- a/packages/netlify-cms-core/src/reducers/__tests__/collections.spec.js +++ b/packages/netlify-cms-core/src/reducers/__tests__/collections.spec.js @@ -460,7 +460,9 @@ describe('collections', () => { ], }); - const updater = field => field.set('default', 'default'); + function updater(field) { + return field.set('default', 'default'); + } expect(updateFieldByKey(collection, 'non-existent', updater)).toBe(collection); expect(updateFieldByKey(collection, 'title', updater)).toEqual( diff --git a/packages/netlify-cms-core/src/reducers/collections.ts b/packages/netlify-cms-core/src/reducers/collections.ts index 49403837..71100c83 100644 --- a/packages/netlify-cms-core/src/reducers/collections.ts +++ b/packages/netlify-cms-core/src/reducers/collections.ts @@ -22,7 +22,7 @@ import { Backend } from '../backend'; const { keyToPathArray } = stringTemplate; -const collections = (state = null, action: CollectionsAction) => { +function collections(state = null, action: CollectionsAction) { switch (action.type) { case CONFIG_SUCCESS: { const configCollections = action.payload @@ -49,7 +49,7 @@ const collections = (state = null, action: CollectionsAction) => { default: return state; } -}; +} const selectors = { [FOLDER]: { @@ -120,7 +120,7 @@ const selectors = { }, }; -const getFieldsWithMediaFolders = (fields: EntryField[]) => { +function getFieldsWithMediaFolders(fields: EntryField[]) { const fieldsWithMediaFolders = fields.reduce((acc, f) => { if (f.has('media_folder')) { acc = [...acc, f]; @@ -141,16 +141,16 @@ const getFieldsWithMediaFolders = (fields: EntryField[]) => { }, [] as EntryField[]); return fieldsWithMediaFolders; -}; +} -export const getFileFromSlug = (collection: Collection, slug: string) => { +export function getFileFromSlug(collection: Collection, slug: string) { return collection .get('files') ?.toArray() .find(f => f.get('name') === slug); -}; +} -export const selectFieldsWithMediaFolders = (collection: Collection, slug: string) => { +export function selectFieldsWithMediaFolders(collection: Collection, slug: string) { if (collection.has('folder')) { const fields = collection.get('fields').toArray(); return getFieldsWithMediaFolders(fields); @@ -163,9 +163,9 @@ export const selectFieldsWithMediaFolders = (collection: Collection, slug: strin } return []; -}; +} -export const selectMediaFolders = (state: State, collection: Collection, entry: EntryMap) => { +export function selectMediaFolders(state: State, collection: Collection, entry: EntryMap) { const fields = selectFieldsWithMediaFolders(collection, entry.get('slug')); const folders = fields.map(f => selectMediaFolder(state.config, collection, entry, f)); if (collection.has('files')) { @@ -181,26 +181,41 @@ export const selectMediaFolders = (state: State, collection: Collection, entry: } return Set(folders).toArray(); -}; +} -export const selectFields = (collection: Collection, slug: string) => - selectors[collection.get('type')].fields(collection, slug); -export const selectFolderEntryExtension = (collection: Collection) => - selectors[FOLDER].entryExtension(collection); -export const selectFileEntryLabel = (collection: Collection, slug: string) => - selectors[FILES].entryLabel(collection, slug); -export const selectEntryPath = (collection: Collection, slug: string) => - selectors[collection.get('type')].entryPath(collection, slug); -export const selectEntrySlug = (collection: Collection, path: string) => - selectors[collection.get('type')].entrySlug(collection, path); -export const selectAllowNewEntries = (collection: Collection) => - selectors[collection.get('type')].allowNewEntries(collection); -export const selectAllowDeletion = (collection: Collection) => - selectors[collection.get('type')].allowDeletion(collection); -export const selectTemplateName = (collection: Collection, slug: string) => - selectors[collection.get('type')].templateName(collection, slug); +export function selectFields(collection: Collection, slug: string) { + return selectors[collection.get('type')].fields(collection, slug); +} -export const getFieldsNames = (fields: EntryField[], prefix = '') => { +export function selectFolderEntryExtension(collection: Collection) { + return selectors[FOLDER].entryExtension(collection); +} + +export function selectFileEntryLabel(collection: Collection, slug: string) { + return selectors[FILES].entryLabel(collection, slug); +} + +export function selectEntryPath(collection: Collection, slug: string) { + return selectors[collection.get('type')].entryPath(collection, slug); +} + +export function selectEntrySlug(collection: Collection, path: string) { + return selectors[collection.get('type')].entrySlug(collection, path); +} + +export function selectAllowNewEntries(collection: Collection) { + return selectors[collection.get('type')].allowNewEntries(collection); +} + +export function selectAllowDeletion(collection: Collection) { + return selectors[collection.get('type')].allowDeletion(collection); +} + +export function selectTemplateName(collection: Collection, slug: string) { + return selectors[collection.get('type')].templateName(collection, slug); +} + +export function getFieldsNames(fields: EntryField[], prefix = '') { let names = fields.map(f => `${prefix}${f.get('name')}`); fields.forEach((f, index) => { @@ -217,9 +232,9 @@ export const getFieldsNames = (fields: EntryField[], prefix = '') => { }); return names; -}; +} -export const selectField = (collection: Collection, key: string) => { +export function selectField(collection: Collection, key: string) { const array = keyToPathArray(key); let name: string | undefined; let field; @@ -236,13 +251,13 @@ export const selectField = (collection: Collection, key: string) => { } return field; -}; +} -export const traverseFields = ( +export function traverseFields( fields: List, updater: (field: EntryField) => EntryField, done = () => false, -) => { +) { if (done()) { return fields; } @@ -268,20 +283,21 @@ export const traverseFields = ( .toList() as List; return fields; -}; +} -export const updateFieldByKey = ( +export function updateFieldByKey( collection: Collection, key: string, updater: (field: EntryField) => EntryField, -) => { +) { const selected = selectField(collection, key); if (!selected) { return collection; } let updated = false; - const updateAndBreak = (f: EntryField) => { + + function updateAndBreak(f: EntryField) { const field = f as EntryField; if (field === selected) { updated = true; @@ -289,7 +305,7 @@ export const updateFieldByKey = ( } else { return field; } - }; + } collection = collection.set( 'fields', @@ -297,18 +313,18 @@ export const updateFieldByKey = ( ); return collection; -}; +} -export const selectIdentifier = (collection: Collection) => { +export function selectIdentifier(collection: Collection) { const identifier = collection.get('identifier_field'); const identifierFields = identifier ? [identifier, ...IDENTIFIER_FIELDS] : IDENTIFIER_FIELDS; const fieldNames = getFieldsNames(collection.get('fields', List()).toArray()); return identifierFields.find(id => fieldNames.find(name => name?.toLowerCase().trim() === id.toLowerCase().trim()), ); -}; +} -export const selectInferedField = (collection: Collection, fieldName: string) => { +export function selectInferedField(collection: Collection, fieldName: string) { if (fieldName === 'title' && collection.get('identifier_field')) { return selectIdentifier(collection); } @@ -355,9 +371,9 @@ export const selectInferedField = (collection: Collection, fieldName: string) => } return null; -}; +} -export const selectEntryCollectionTitle = (collection: Collection, entry: EntryMap) => { +export function selectEntryCollectionTitle(collection: Collection, entry: EntryMap) { // prefer formatted summary over everything else const summaryTemplate = collection.get('summary'); if (summaryTemplate) return summaryFormatter(summaryTemplate, entry, collection); @@ -372,16 +388,16 @@ export const selectEntryCollectionTitle = (collection: Collection, entry: EntryM const entryData = entry.get('data'); const titleField = selectInferedField(collection, 'title'); return titleField && entryData.getIn(keyToPathArray(titleField)); -}; +} export const COMMIT_AUTHOR = 'commit_author'; export const COMMIT_DATE = 'commit_date'; -export const selectDefaultSortableFields = ( +export function selectDefaultSortableFields( collection: Collection, backend: Backend, hasIntegration: boolean, -) => { +) { let defaultSortable = SORTABLE_FIELDS.map((type: string) => { const field = selectInferedField(collection, type); if (backend.isGitBackend() && type === 'author' && !field && !hasIntegration) { @@ -397,9 +413,9 @@ export const selectDefaultSortableFields = ( } return defaultSortable as string[]; -}; +} -export const selectSortableFields = (collection: Collection, t: (key: string) => string) => { +export function selectSortableFields(collection: Collection, t: (key: string) => string) { const fields = collection .get('sortable_fields') .toArray() @@ -418,9 +434,9 @@ export const selectSortableFields = (collection: Collection, t: (key: string) => .map(item => ({ ...item.field, key: item.key })); return fields; -}; +} -export const selectSortDataPath = (collection: Collection, key: string) => { +export function selectSortDataPath(collection: Collection, key: string) { if (key === COMMIT_DATE) { return 'updatedOn'; } else if (key === COMMIT_AUTHOR && !selectField(collection, key)) { @@ -428,19 +444,19 @@ export const selectSortDataPath = (collection: Collection, key: string) => { } else { return `data.${key}`; } -}; +} -export const selectViewFilters = (collection: Collection) => { +export function selectViewFilters(collection: Collection) { const viewFilters = collection.get('view_filters').toJS() as ViewFilter[]; return viewFilters; -}; +} -export const selectViewGroups = (collection: Collection) => { +export function selectViewGroups(collection: Collection) { const viewGroups = collection.get('view_groups').toJS() as ViewGroup[]; return viewGroups; -}; +} -export const selectFieldsComments = (collection: Collection, entryMap: EntryMap) => { +export function selectFieldsComments(collection: Collection, entryMap: EntryMap) { let fields: EntryField[] = []; if (collection.has('folder')) { fields = collection.get('fields').toArray(); @@ -458,15 +474,15 @@ export const selectFieldsComments = (collection: Collection, entryMap: EntryMap) }); return comments; -}; +} -export const selectHasMetaPath = (collection: Collection) => { +export function selectHasMetaPath(collection: Collection) { return ( collection.has('folder') && collection.get('type') === FOLDER && collection.has('meta') && collection.get('meta')?.has('path') ); -}; +} export default collections; diff --git a/packages/netlify-cms-core/src/reducers/combinedReducer.js b/packages/netlify-cms-core/src/reducers/combinedReducer.js index 726fe922..f38b9f46 100644 --- a/packages/netlify-cms-core/src/reducers/combinedReducer.js +++ b/packages/netlify-cms-core/src/reducers/combinedReducer.js @@ -3,12 +3,12 @@ import { connectRouter } from 'connected-react-router'; import { reducer as notifReducer } from 'redux-notifications'; import reducers from './index'; -const createRootReducer = history => { +function createRootReducer(history) { return combineReducers({ ...reducers, notifs: notifReducer, router: connectRouter(history), }); -}; +} export default createRootReducer; diff --git a/packages/netlify-cms-core/src/reducers/config.ts b/packages/netlify-cms-core/src/reducers/config.ts index 0e55d46c..24cd00d3 100644 --- a/packages/netlify-cms-core/src/reducers/config.ts +++ b/packages/netlify-cms-core/src/reducers/config.ts @@ -5,7 +5,7 @@ import { EDITORIAL_WORKFLOW } from '../constants/publishModes'; const defaultState: Map = Map({ isFetching: true }); -const config = (state = defaultState, action: ConfigAction) => { +function config(state = defaultState, action: ConfigAction) { switch (action.type) { case CONFIG_REQUEST: return state.set('isFetching', true); @@ -24,11 +24,14 @@ const config = (state = defaultState, action: ConfigAction) => { default: return state; } -}; +} -export const selectLocale = (state: Config) => state.get('locale', 'en') as string; +export function selectLocale(state: Config) { + return state.get('locale', 'en') as string; +} -export const selectUseWorkflow = (state: Config) => - state.get('publish_mode') === EDITORIAL_WORKFLOW; +export function selectUseWorkflow(state: Config) { + return state.get('publish_mode') === EDITORIAL_WORKFLOW; +} export default config; diff --git a/packages/netlify-cms-core/src/reducers/cursors.js b/packages/netlify-cms-core/src/reducers/cursors.js index 4a43cd26..00a492b4 100644 --- a/packages/netlify-cms-core/src/reducers/cursors.js +++ b/packages/netlify-cms-core/src/reducers/cursors.js @@ -10,10 +10,11 @@ import { // Since pagination can be used for a variety of views (collections // and searches are the most common examples), we namespace cursors by // their type before storing them in the state. -export const selectCollectionEntriesCursor = (state, collectionName) => - new Cursor(state.getIn(['cursorsByType', 'collectionEntries', collectionName])); +export function selectCollectionEntriesCursor(state, collectionName) { + return new Cursor(state.getIn(['cursorsByType', 'collectionEntries', collectionName])); +} -const cursors = (state = fromJS({ cursorsByType: { collectionEntries: {} } }), action) => { +function cursors(state = fromJS({ cursorsByType: { collectionEntries: {} } }), action) { switch (action.type) { case ENTRIES_SUCCESS: { return state.setIn( @@ -29,6 +30,6 @@ const cursors = (state = fromJS({ cursorsByType: { collectionEntries: {} } }), a default: return state; } -}; +} export default cursors; diff --git a/packages/netlify-cms-core/src/reducers/deploys.js b/packages/netlify-cms-core/src/reducers/deploys.js index e5580daa..db29d4c8 100644 --- a/packages/netlify-cms-core/src/reducers/deploys.js +++ b/packages/netlify-cms-core/src/reducers/deploys.js @@ -5,7 +5,7 @@ import { DEPLOY_PREVIEW_FAILURE, } from 'Actions/deploys'; -const deploys = (state = Map({ deploys: Map() }), action) => { +function deploys(state = Map({ deploys: Map() }), action) { switch (action.type) { case DEPLOY_PREVIEW_REQUEST: { const { collection, slug } = action.payload; @@ -37,9 +37,10 @@ const deploys = (state = Map({ deploys: Map() }), action) => { default: return state; } -}; +} -export const selectDeployPreview = (state, collection, slug) => - state.getIn(['deploys', `${collection}.${slug}`]); +export function selectDeployPreview(state, collection, slug) { + return state.getIn(['deploys', `${collection}.${slug}`]); +} export default deploys; diff --git a/packages/netlify-cms-core/src/reducers/editorialWorkflow.ts b/packages/netlify-cms-core/src/reducers/editorialWorkflow.ts index 9326e0d8..4f7c326c 100644 --- a/packages/netlify-cms-core/src/reducers/editorialWorkflow.ts +++ b/packages/netlify-cms-core/src/reducers/editorialWorkflow.ts @@ -21,7 +21,7 @@ import { import { CONFIG_SUCCESS } from '../actions/config'; import { EditorialWorkflowAction, EditorialWorkflow, Entities } from '../types/redux'; -const unpublishedEntries = (state = Map(), action: EditorialWorkflowAction) => { +function unpublishedEntries(state = Map(), action: EditorialWorkflowAction) { switch (action.type) { case CONFIG_SUCCESS: { const publishMode = action.payload && action.payload.get('publish_mode'); @@ -137,27 +137,25 @@ const unpublishedEntries = (state = Map(), action: EditorialWorkflowAction) => { default: return state; } -}; +} -export const selectUnpublishedEntry = ( - state: EditorialWorkflow, - collection: string, - slug: string, -) => state && state.getIn(['entities', `${collection}.${slug}`]); +export function selectUnpublishedEntry(state: EditorialWorkflow, collection: string, slug: string) { + return state && state.getIn(['entities', `${collection}.${slug}`]); +} -export const selectUnpublishedEntriesByStatus = (state: EditorialWorkflow, status: string) => { +export function selectUnpublishedEntriesByStatus(state: EditorialWorkflow, status: string) { if (!state) return null; const entities = state.get('entities') as Entities; return entities.filter(entry => entry.get('status') === status).valueSeq(); -}; +} -export const selectUnpublishedSlugs = (state: EditorialWorkflow, collection: string) => { +export function selectUnpublishedSlugs(state: EditorialWorkflow, collection: string) { if (!state.get('entities')) return null; const entities = state.get('entities') as Entities; return entities .filter((_v, k) => startsWith(k as string, `${collection}.`)) .map(entry => entry.get('slug')) .valueSeq(); -}; +} export default unpublishedEntries; diff --git a/packages/netlify-cms-core/src/reducers/entries.ts b/packages/netlify-cms-core/src/reducers/entries.ts index 70e1fa1e..7240b424 100644 --- a/packages/netlify-cms-core/src/reducers/entries.ts +++ b/packages/netlify-cms-core/src/reducers/entries.ts @@ -95,11 +95,11 @@ const loadSort = once(() => { return Map() as Sort; }); -const clearSort = () => { +function clearSort() { localStorage.removeItem(storageSortKey); -}; +} -const persistSort = (sort: Sort | undefined) => { +function persistSort(sort: Sort | undefined) { if (sort) { const storageSort: StorageSort = {}; sort.keySeq().forEach(key => { @@ -117,7 +117,7 @@ const persistSort = (sort: Sort | undefined) => { } else { clearSort(); } -}; +} const loadViewStyle = once(() => { const viewStyle = localStorage.getItem(viewStyleKey); @@ -129,22 +129,22 @@ const loadViewStyle = once(() => { return VIEW_STYLE_LIST; }); -const clearViewStyle = () => { +function clearViewStyle() { localStorage.removeItem(viewStyleKey); -}; +} -const persistViewStyle = (viewStyle: string | undefined) => { +function persistViewStyle(viewStyle: string | undefined) { if (viewStyle) { localStorage.setItem(viewStyleKey, viewStyle); } else { clearViewStyle(); } -}; +} -const entries = ( +function entries( state = Map({ entities: Map(), pages: Map(), sort: loadSort(), viewStyle: loadViewStyle() }), action: EntriesAction, -) => { +) { switch (action.type) { case ENTRY_REQUEST: { const payload = action.payload as EntryRequestPayload; @@ -344,30 +344,30 @@ const entries = ( default: return state; } -}; +} -export const selectEntriesSort = (entries: Entries, collection: string) => { +export function selectEntriesSort(entries: Entries, collection: string) { const sort = entries.get('sort') as Sort | undefined; return sort?.get(collection); -}; +} -export const selectEntriesFilter = (entries: Entries, collection: string) => { +export function selectEntriesFilter(entries: Entries, collection: string) { const filter = entries.get('filter') as Filter | undefined; return filter?.get(collection) || Map(); -}; +} -export const selectEntriesGroup = (entries: Entries, collection: string) => { +export function selectEntriesGroup(entries: Entries, collection: string) { const group = entries.get('group') as Group | undefined; return group?.get(collection) || Map(); -}; +} -export const selectEntriesGroupField = (entries: Entries, collection: string) => { +export function selectEntriesGroupField(entries: Entries, collection: string) { const groups = selectEntriesGroup(entries, collection); const value = groups?.valueSeq().find(v => v?.get('active') === true); return value; -}; +} -export const selectEntriesSortFields = (entries: Entries, collection: string) => { +export function selectEntriesSortFields(entries: Entries, collection: string) { const sort = selectEntriesSort(entries, collection); const values = sort @@ -376,9 +376,9 @@ export const selectEntriesSortFields = (entries: Entries, collection: string) => .toArray() || []; return values; -}; +} -export const selectEntriesFilterFields = (entries: Entries, collection: string) => { +export function selectEntriesFilterFields(entries: Entries, collection: string) { const filter = selectEntriesFilter(entries, collection); const values = filter @@ -386,27 +386,29 @@ export const selectEntriesFilterFields = (entries: Entries, collection: string) .filter(v => v?.get('active') === true) .toArray() || []; return values; -}; +} -export const selectViewStyle = (entries: Entries) => { +export function selectViewStyle(entries: Entries) { return entries.get('viewStyle'); -}; +} -export const selectEntry = (state: Entries, collection: string, slug: string) => - state.getIn(['entities', `${collection}.${slug}`]); +export function selectEntry(state: Entries, collection: string, slug: string) { + return state.getIn(['entities', `${collection}.${slug}`]); +} -export const selectPublishedSlugs = (state: Entries, collection: string) => - state.getIn(['pages', collection, 'ids'], List()); +export function selectPublishedSlugs(state: Entries, collection: string) { + return state.getIn(['pages', collection, 'ids'], List()); +} -const getPublishedEntries = (state: Entries, collectionName: string) => { +function getPublishedEntries(state: Entries, collectionName: string) { const slugs = selectPublishedSlugs(state, collectionName); const entries = slugs && (slugs.map(slug => selectEntry(state, collectionName, slug as string)) as List); return entries; -}; +} -export const selectEntries = (state: Entries, collection: Collection) => { +export function selectEntries(state: Entries, collection: Collection) { const collectionName = collection.get('name'); let entries = getPublishedEntries(state, collectionName); @@ -438,9 +440,9 @@ export const selectEntries = (state: Entries, collection: Collection) => { } return entries; -}; +} -const getGroup = (entry: EntryMap, selectedGroup: GroupMap) => { +function getGroup(entry: EntryMap, selectedGroup: GroupMap) { const label = selectedGroup.get('label'); const field = selectedGroup.get('field'); @@ -478,9 +480,9 @@ const getGroup = (entry: EntryMap, selectedGroup: GroupMap) => { label, value: typeof fieldData === 'boolean' ? fieldData : dataAsString, }; -}; +} -export const selectGroups = (state: Entries, collection: Collection) => { +export function selectGroups(state: Entries, collection: Collection) { const collectionName = collection.get('name'); const entries = getPublishedEntries(state, collectionName); @@ -507,37 +509,37 @@ export const selectGroups = (state: Entries, collection: Collection) => { }); return groupsArray; -}; +} -export const selectEntryByPath = (state: Entries, collection: string, path: string) => { +export function selectEntryByPath(state: Entries, collection: string, path: string) { const slugs = selectPublishedSlugs(state, collection); const entries = slugs && (slugs.map(slug => selectEntry(state, collection, slug as string)) as List); return entries && entries.find(e => e?.get('path') === path); -}; +} -export const selectEntriesLoaded = (state: Entries, collection: string) => { +export function selectEntriesLoaded(state: Entries, collection: string) { return !!state.getIn(['pages', collection]); -}; +} -export const selectIsFetching = (state: Entries, collection: string) => { +export function selectIsFetching(state: Entries, collection: string) { return state.getIn(['pages', collection, 'isFetching'], false); -}; +} const DRAFT_MEDIA_FILES = 'DRAFT_MEDIA_FILES'; -const getFileField = (collectionFiles: CollectionFiles, slug: string | undefined) => { +function getFileField(collectionFiles: CollectionFiles, slug: string | undefined) { const file = collectionFiles.find(f => f?.get('name') === slug); return file; -}; +} -const hasCustomFolder = ( +function hasCustomFolder( folderKey: 'media_folder' | 'public_folder', collection: Collection | null, slug: string | undefined, field: EntryField | undefined, -) => { +) { if (!collection) { return false; } @@ -558,9 +560,9 @@ const hasCustomFolder = ( } return false; -}; +} -const traverseFields = ( +function traverseFields( folderKey: 'media_folder' | 'public_folder', config: Config, collection: Collection, @@ -568,7 +570,7 @@ const traverseFields = ( field: EntryField, fields: EntryField[], currentFolder: string, -): string | null => { +): string | null { const matchedField = fields.filter(f => f === field)[0]; if (matchedField) { return folderFormatter( @@ -632,15 +634,15 @@ const traverseFields = ( } return null; -}; +} -const evaluateFolder = ( +function evaluateFolder( folderKey: 'media_folder' | 'public_folder', config: Config, collection: Collection, entryMap: EntryMap | undefined, field: EntryField | undefined, -) => { +) { let currentFolder = config.get(folderKey); // add identity template if doesn't exist @@ -723,14 +725,14 @@ const evaluateFolder = ( } return currentFolder; -}; +} -export const selectMediaFolder = ( +export function selectMediaFolder( config: Config, collection: Collection | null, entryMap: EntryMap | undefined, field: EntryField | undefined, -) => { +) { const name = 'media_folder'; let mediaFolder = config.get(name); @@ -750,15 +752,15 @@ export const selectMediaFolder = ( } return trim(mediaFolder, '/'); -}; +} -export const selectMediaFilePath = ( +export function selectMediaFilePath( config: Config, collection: Collection | null, entryMap: EntryMap | undefined, mediaPath: string, field: EntryField | undefined, -) => { +) { if (isAbsolutePath(mediaPath)) { return mediaPath; } @@ -766,15 +768,15 @@ export const selectMediaFilePath = ( const mediaFolder = selectMediaFolder(config, collection, entryMap, field); return join(mediaFolder, basename(mediaPath)); -}; +} -export const selectMediaFilePublicPath = ( +export function selectMediaFilePublicPath( config: Config, collection: Collection | null, mediaPath: string, entryMap: EntryMap | undefined, field: EntryField | undefined, -) => { +) { if (isAbsolutePath(mediaPath)) { return mediaPath; } @@ -789,12 +791,12 @@ export const selectMediaFilePublicPath = ( } return join(publicFolder, basename(mediaPath)); -}; +} -export const selectEditingDraft = (state: EntryDraft) => { +export function selectEditingDraft(state: EntryDraft) { const entry = state.get('entry'); const workflowDraft = entry && !entry.isEmpty(); return workflowDraft; -}; +} export default entries; diff --git a/packages/netlify-cms-core/src/reducers/entryDraft.js b/packages/netlify-cms-core/src/reducers/entryDraft.js index ce8f824d..d59322b5 100644 --- a/packages/netlify-cms-core/src/reducers/entryDraft.js +++ b/packages/netlify-cms-core/src/reducers/entryDraft.js @@ -35,7 +35,7 @@ const initialState = Map({ key: '', }); -const entryDraftReducer = (state = Map(), action) => { +function entryDraftReducer(state = Map(), action) { switch (action.type) { case DRAFT_CREATE_FROM_ENTRY: // Existing Entry @@ -180,9 +180,9 @@ const entryDraftReducer = (state = Map(), action) => { default: return state; } -}; +} -export const selectCustomPath = (collection, entryDraft) => { +export function selectCustomPath(collection, entryDraft) { if (!selectHasMetaPath(collection)) { return; } @@ -192,6 +192,6 @@ export const selectCustomPath = (collection, entryDraft) => { const extension = selectFolderEntryExtension(collection); const customPath = path && join(collection.get('folder'), path, `${indexFile}.${extension}`); return customPath; -}; +} export default entryDraftReducer; diff --git a/packages/netlify-cms-core/src/reducers/globalUI.js b/packages/netlify-cms-core/src/reducers/globalUI.js index 04d06af2..5f2e0862 100644 --- a/packages/netlify-cms-core/src/reducers/globalUI.js +++ b/packages/netlify-cms-core/src/reducers/globalUI.js @@ -8,12 +8,14 @@ const LOADING_IGNORE_LIST = [ 'STATUS_FAILURE', ]; -const ignoreWhenLoading = action => LOADING_IGNORE_LIST.some(type => action.type.includes(type)); +function ignoreWhenLoading(action) { + return LOADING_IGNORE_LIST.some(type => action.type.includes(type)); +} -/* +/** * Reducer for some global UI state that we want to share between components - * */ -const globalUI = (state = Map({ isFetching: false, useOpenAuthoring: false }), action) => { + */ +function globalUI(state = Map({ isFetching: false, useOpenAuthoring: false }), action) { // Generic, global loading indicator if (!ignoreWhenLoading(action) && action.type.includes('REQUEST')) { return state.set('isFetching', true); @@ -26,6 +28,6 @@ const globalUI = (state = Map({ isFetching: false, useOpenAuthoring: false }), a return state.set('useOpenAuthoring', true); } return state; -}; +} export default globalUI; diff --git a/packages/netlify-cms-core/src/reducers/index.ts b/packages/netlify-cms-core/src/reducers/index.ts index af5fdd25..e5bbbe7a 100644 --- a/packages/netlify-cms-core/src/reducers/index.ts +++ b/packages/netlify-cms-core/src/reducers/index.ts @@ -37,16 +37,19 @@ export default reducers; /* * Selectors */ -export const selectEntry = (state: State, collection: string, slug: string) => - fromEntries.selectEntry(state.entries, collection, slug); +export function selectEntry(state: State, collection: string, slug: string) { + return fromEntries.selectEntry(state.entries, collection, slug); +} -export const selectEntries = (state: State, collection: Collection) => - fromEntries.selectEntries(state.entries, collection); +export function selectEntries(state: State, collection: Collection) { + return fromEntries.selectEntries(state.entries, collection); +} -export const selectPublishedSlugs = (state: State, collection: string) => - fromEntries.selectPublishedSlugs(state.entries, collection); +export function selectPublishedSlugs(state: State, collection: string) { + return fromEntries.selectPublishedSlugs(state.entries, collection); +} -export const selectSearchedEntries = (state: State, availableCollections: string[]) => { +export function selectSearchedEntries(state: State, availableCollections: string[]) { const searchItems = state.search.get('entryIds'); // only return search results for actually available collections return ( @@ -55,19 +58,24 @@ export const selectSearchedEntries = (state: State, availableCollections: string .filter(({ collection }) => availableCollections.indexOf(collection) !== -1) .map(({ collection, slug }) => fromEntries.selectEntry(state.entries, collection, slug)) ); -}; +} -export const selectDeployPreview = (state: State, collection: string, slug: string) => - fromDeploys.selectDeployPreview(state.deploys, collection, slug); +export function selectDeployPreview(state: State, collection: string, slug: string) { + return fromDeploys.selectDeployPreview(state.deploys, collection, slug); +} -export const selectUnpublishedEntry = (state: State, collection: string, slug: string) => - fromEditorialWorkflow.selectUnpublishedEntry(state.editorialWorkflow, collection, slug); +export function selectUnpublishedEntry(state: State, collection: string, slug: string) { + return fromEditorialWorkflow.selectUnpublishedEntry(state.editorialWorkflow, collection, slug); +} -export const selectUnpublishedEntriesByStatus = (state: State, status: Status) => - fromEditorialWorkflow.selectUnpublishedEntriesByStatus(state.editorialWorkflow, status); +export function selectUnpublishedEntriesByStatus(state: State, status: Status) { + return fromEditorialWorkflow.selectUnpublishedEntriesByStatus(state.editorialWorkflow, status); +} -export const selectUnpublishedSlugs = (state: State, collection: string) => - fromEditorialWorkflow.selectUnpublishedSlugs(state.editorialWorkflow, collection); +export function selectUnpublishedSlugs(state: State, collection: string) { + return fromEditorialWorkflow.selectUnpublishedSlugs(state.editorialWorkflow, collection); +} -export const selectIntegration = (state: State, collection: string | null, hook: string) => - fromIntegrations.selectIntegration(state.integrations, collection, hook); +export function selectIntegration(state: State, collection: string | null, hook: string) { + return fromIntegrations.selectIntegration(state.integrations, collection, hook); +} diff --git a/packages/netlify-cms-core/src/reducers/integrations.ts b/packages/netlify-cms-core/src/reducers/integrations.ts index 9a77b5cc..17c112d3 100644 --- a/packages/netlify-cms-core/src/reducers/integrations.ts +++ b/packages/netlify-cms-core/src/reducers/integrations.ts @@ -7,7 +7,7 @@ interface Acc { hooks: Record>; } -export const getIntegrations = (config: Config) => { +export function getIntegrations(config: Config) { const integrations: Integration[] = config.get('integrations', List()).toJS() || []; const newState = integrations.reduce( (acc, integration) => { @@ -38,9 +38,9 @@ export const getIntegrations = (config: Config) => { { providers: {}, hooks: {} } as Acc, ); return fromJS(newState); -}; +} -const integrations = (state = null, action: IntegrationsAction): Integrations | null => { +function integrations(state = null, action: IntegrationsAction): Integrations | null { switch (action.type) { case CONFIG_SUCCESS: { return getIntegrations(action.payload); @@ -48,11 +48,12 @@ const integrations = (state = null, action: IntegrationsAction): Integrations | default: return state; } -}; +} -export const selectIntegration = (state: Integrations, collection: string | null, hook: string) => - collection +export function selectIntegration(state: Integrations, collection: string | null, hook: string) { + return collection ? state.getIn(['hooks', collection, hook], false) : state.getIn(['hooks', hook], false); +} export default integrations; diff --git a/packages/netlify-cms-core/src/reducers/mediaLibrary.ts b/packages/netlify-cms-core/src/reducers/mediaLibrary.ts index e2a6cbb1..b9c089d1 100644 --- a/packages/netlify-cms-core/src/reducers/mediaLibrary.ts +++ b/packages/netlify-cms-core/src/reducers/mediaLibrary.ts @@ -51,7 +51,7 @@ const defaultState: { config: Map(), }; -const mediaLibrary = (state = Map(defaultState), action: MediaLibraryAction) => { +function mediaLibrary(state = Map(defaultState), action: MediaLibraryAction) { switch (action.type) { case MEDIA_LIBRARY_CREATE: return state.withMutations(map => { @@ -213,7 +213,7 @@ const mediaLibrary = (state = Map(defaultState), action: MediaLibraryAction) => default: return state; } -}; +} export function selectMediaFiles(state: State, field?: EntryField) { const { mediaLibrary, entryDraft } = state; diff --git a/packages/netlify-cms-core/src/reducers/medias.ts b/packages/netlify-cms-core/src/reducers/medias.ts index 0b6f2649..70de7fbd 100644 --- a/packages/netlify-cms-core/src/reducers/medias.ts +++ b/packages/netlify-cms-core/src/reducers/medias.ts @@ -57,7 +57,8 @@ const medias = produce((state: Medias, action: MediasAction) => { } }, defaultState); -export const selectIsLoadingAsset = (state: Medias) => - Object.values(state).some(state => state.isLoading); +export function selectIsLoadingAsset(state: Medias) { + return Object.values(state).some(state => state.isLoading); +} export default medias; diff --git a/packages/netlify-cms-core/src/reducers/search.js b/packages/netlify-cms-core/src/reducers/search.js index 9a6b7cb7..7e4bef6c 100644 --- a/packages/netlify-cms-core/src/reducers/search.js +++ b/packages/netlify-cms-core/src/reducers/search.js @@ -23,7 +23,7 @@ const defaultState = Map({ queryHits: Map({}), }); -const entries = (state = defaultState, action) => { +function entries(state = defaultState, action) { switch (action.type) { case SEARCH_CLEAR: return defaultState; @@ -84,6 +84,6 @@ const entries = (state = defaultState, action) => { default: return state; } -}; +} export default entries; diff --git a/packages/netlify-cms-core/src/redux/middleware/waitUntilAction.ts b/packages/netlify-cms-core/src/redux/middleware/waitUntilAction.ts index f22ff5fe..6645a524 100644 --- a/packages/netlify-cms-core/src/redux/middleware/waitUntilAction.ts +++ b/packages/netlify-cms-core/src/redux/middleware/waitUntilAction.ts @@ -21,6 +21,7 @@ interface WaitAction extends WaitActionArgs { type: typeof WAIT_UNTIL_ACTION; } +// eslint-disable-next-line func-style export const waitUntilAction: Middleware<{}, State, Dispatch> = ({ dispatch, getState, @@ -50,7 +51,7 @@ export const waitUntilAction: Middleware<{}, State, Dispatch> = ({ } } - return (next: Dispatch) => (action: AnyAction): null | AnyAction => { + return (next: Dispatch) => (action: AnyAction): null | AnyAction => { if (action.type === WAIT_UNTIL_ACTION) { pending.push(action as WaitAction); return null; diff --git a/packages/netlify-cms-core/src/routing/history.ts b/packages/netlify-cms-core/src/routing/history.ts index 9a2b5db5..e24c0a80 100644 --- a/packages/netlify-cms-core/src/routing/history.ts +++ b/packages/netlify-cms-core/src/routing/history.ts @@ -2,11 +2,16 @@ import { createHashHistory } from 'history'; const history = createHashHistory(); -export const navigateToCollection = (collectionName: string) => - history.push(`/collections/${collectionName}`); -export const navigateToNewEntry = (collectionName: string) => - history.replace(`/collections/${collectionName}/new`); -export const navigateToEntry = (collectionName: string, slug: string) => - history.replace(`/collections/${collectionName}/entries/${slug}`); +export function navigateToCollection(collectionName: string) { + return history.push(`/collections/${collectionName}`); +} + +export function navigateToNewEntry(collectionName: string) { + return history.replace(`/collections/${collectionName}/new`); +} + +export function navigateToEntry(collectionName: string, slug: string) { + return history.replace(`/collections/${collectionName}/entries/${slug}`); +} export default history; diff --git a/packages/netlify-cms-core/src/valueObjects/EditorComponent.js b/packages/netlify-cms-core/src/valueObjects/EditorComponent.js index 40b8aaa7..cc7a99f2 100644 --- a/packages/netlify-cms-core/src/valueObjects/EditorComponent.js +++ b/packages/netlify-cms-core/src/valueObjects/EditorComponent.js @@ -2,7 +2,10 @@ import { fromJS } from 'immutable'; import { isFunction } from 'lodash'; const catchesNothing = /.^/; -const bind = fn => isFunction(fn) && fn.bind(null); + +function bind(fn) { + return isFunction(fn) && fn.bind(null); +} export default function createEditorComponent(config) { const { diff --git a/packages/netlify-cms-core/webpack.config.js b/packages/netlify-cms-core/webpack.config.js index 7b5d3c68..97a7c793 100644 --- a/packages/netlify-cms-core/webpack.config.js +++ b/packages/netlify-cms-core/webpack.config.js @@ -8,13 +8,13 @@ const versionPlugin = new webpack.DefinePlugin({ NETLIFY_CMS_CORE_VERSION: JSON.stringify(`${pkg.version}${isProduction ? '' : '-dev'}`), }); -const configs = () => { +function configs() { return getConfig().map(config => { return { ...config, plugins: [...config.plugins, versionPlugin], }; }); -}; +} module.exports = configs(); diff --git a/packages/netlify-cms-editor-component-image/src/__tests__/index.spec.js b/packages/netlify-cms-editor-component-image/src/__tests__/index.spec.js index 6468dfc6..325df448 100644 --- a/packages/netlify-cms-editor-component-image/src/__tests__/index.spec.js +++ b/packages/netlify-cms-editor-component-image/src/__tests__/index.spec.js @@ -1,6 +1,9 @@ import component from '../index'; -const getAsset = path => path; +function getAsset(path) { + return path; +} + const image = '/image'; const alt = 'alt'; const title = 'title'; diff --git a/packages/netlify-cms-lib-util/src/API.ts b/packages/netlify-cms-lib-util/src/API.ts index 628d23c9..e9ea8196 100644 --- a/packages/netlify-cms-lib-util/src/API.ts +++ b/packages/netlify-cms-lib-util/src/API.ts @@ -38,11 +38,11 @@ class RateLimitError extends Error { } } -export const requestWithBackoff = async ( +export async function requestWithBackoff( api: API, req: ApiRequest, attempt = 1, -): Promise => { +): Promise { if (api.rateLimiter) { await api.rateLimiter.acquire(); } @@ -92,14 +92,14 @@ export const requestWithBackoff = async ( return requestWithBackoff(api, req, attempt + 1); } } -}; +} -export const readFile = async ( +export async function readFile( id: string | null | undefined, fetchContent: () => Promise, localForage: LocalForage, isText: boolean, -) => { +) { const key = id ? (isText ? `gh.${id}` : `gh.${id}.blob`) : null; const cached = key ? await localForage.getItem(key) : null; if (cached) { @@ -111,20 +111,22 @@ export const readFile = async ( await localForage.setItem(key, content); } return content; -}; +} export type FileMetadata = { author: string; updatedOn: string; }; -const getFileMetadataKey = (id: string) => `gh.${id}.meta`; +function getFileMetadataKey(id: string) { + return `gh.${id}.meta`; +} -export const readFileMetadata = async ( +export async function readFileMetadata( id: string | null | undefined, fetchMetadata: () => Promise, localForage: LocalForage, -) => { +) { const key = id ? getFileMetadataKey(id) : null; const cached = key && (await localForage.getItem(key)); if (cached) { @@ -136,7 +138,7 @@ export const readFileMetadata = async ( await localForage.setItem(key, metadata); } return metadata; -}; +} /** * Keywords for inferring a status that will provide a deploy preview URL. @@ -148,12 +150,12 @@ const PREVIEW_CONTEXT_KEYWORDS = ['deploy']; * deploy preview. Checks for an exact match against `previewContext` if given, * otherwise checks for inclusion of a value from `PREVIEW_CONTEXT_KEYWORDS`. */ -export const isPreviewContext = (context: string, previewContext: string) => { +export function isPreviewContext(context: string, previewContext: string) { if (previewContext) { return context === previewContext; } return PREVIEW_CONTEXT_KEYWORDS.some(keyword => context.includes(keyword)); -}; +} export enum PreviewState { Other = 'other', @@ -164,20 +166,20 @@ export enum PreviewState { * Retrieve a deploy preview URL from an array of statuses. By default, a * matching status is inferred via `isPreviewContext`. */ -export const getPreviewStatus = ( +export function getPreviewStatus( statuses: { context: string; target_url: string; state: PreviewState; }[], previewContext: string, -) => { +) { return statuses.find(({ context }) => { return isPreviewContext(context, previewContext); }); -}; +} -const getConflictingBranches = (branchName: string) => { +function getConflictingBranches(branchName: string) { // for cms/posts/post-1, conflicting branches are cms/posts, cms const parts = branchName.split('/'); parts.pop(); @@ -188,13 +190,13 @@ const getConflictingBranches = (branchName: string) => { }, [] as string[]); return conflictingBranches; -}; +} -export const throwOnConflictingBranches = async ( +export async function throwOnConflictingBranches( branchName: string, getBranch: (name: string) => Promise<{ name: string }>, apiName: string, -) => { +) { const possibleConflictingBranches = getConflictingBranches(branchName); const conflictingBranches = await Promise.all( @@ -213,4 +215,4 @@ export const throwOnConflictingBranches = async ( apiName, ); } -}; +} diff --git a/packages/netlify-cms-lib-util/src/APIUtils.ts b/packages/netlify-cms-lib-util/src/APIUtils.ts index d7306e90..49a9a0c2 100644 --- a/packages/netlify-cms-lib-util/src/APIUtils.ts +++ b/packages/netlify-cms-lib-util/src/APIUtils.ts @@ -3,27 +3,36 @@ export const DEFAULT_PR_BODY = 'Automatically generated by Netlify CMS'; export const MERGE_COMMIT_MESSAGE = 'Automatically generated. Merged on Netlify CMS.'; const DEFAULT_NETLIFY_CMS_LABEL_PREFIX = 'netlify-cms/'; -const getLabelPrefix = (labelPrefix: string) => labelPrefix || DEFAULT_NETLIFY_CMS_LABEL_PREFIX; -export const isCMSLabel = (label: string, labelPrefix: string) => - label.startsWith(getLabelPrefix(labelPrefix)); -export const labelToStatus = (label: string, labelPrefix: string) => - label.substr(getLabelPrefix(labelPrefix).length); -export const statusToLabel = (status: string, labelPrefix: string) => - `${getLabelPrefix(labelPrefix)}${status}`; +function getLabelPrefix(labelPrefix: string) { + return labelPrefix || DEFAULT_NETLIFY_CMS_LABEL_PREFIX; +} -export const generateContentKey = (collectionName: string, slug: string) => - `${collectionName}/${slug}`; +export function isCMSLabel(label: string, labelPrefix: string) { + return label.startsWith(getLabelPrefix(labelPrefix)); +} -export const parseContentKey = (contentKey: string) => { +export function labelToStatus(label: string, labelPrefix: string) { + return label.substr(getLabelPrefix(labelPrefix).length); +} + +export function statusToLabel(status: string, labelPrefix: string) { + return `${getLabelPrefix(labelPrefix)}${status}`; +} + +export function generateContentKey(collectionName: string, slug: string) { + return `${collectionName}/${slug}`; +} + +export function parseContentKey(contentKey: string) { const index = contentKey.indexOf('/'); return { collection: contentKey.substr(0, index), slug: contentKey.substr(index + 1) }; -}; +} -export const contentKeyFromBranch = (branch: string) => { +export function contentKeyFromBranch(branch: string) { return branch.substring(`${CMS_BRANCH_PREFIX}/`.length); -}; +} -export const branchFromContentKey = (contentKey: string) => { +export function branchFromContentKey(contentKey: string) { return `${CMS_BRANCH_PREFIX}/${contentKey}`; -}; +} diff --git a/packages/netlify-cms-lib-util/src/Cursor.ts b/packages/netlify-cms-lib-util/src/Cursor.ts index 35ac2922..4edd5cdc 100644 --- a/packages/netlify-cms-lib-util/src/Cursor.ts +++ b/packages/netlify-cms-lib-util/src/Cursor.ts @@ -27,7 +27,7 @@ export type CursorStore = { type ActionHandler = (action: string) => unknown; -const jsToMap = (obj: {}) => { +function jsToMap(obj: {}) { if (obj === undefined) { return Map(); } @@ -36,7 +36,7 @@ const jsToMap = (obj: {}) => { throw new Error('Object must be equivalent to a Map.'); } return immutableObj; -}; +} const knownMetaKeys = Set([ 'index', @@ -49,8 +49,10 @@ const knownMetaKeys = Set([ 'folder', 'depth', ]); -const filterUnknownMetaKeys = (meta: Map) => - meta.filter((_v, k) => knownMetaKeys.has(k as string)); + +function filterUnknownMetaKeys(meta: Map) { + return meta.filter((_v, k) => knownMetaKeys.has(k as string)); +} /* createCursorMap takes one of three signatures: @@ -58,7 +60,7 @@ const filterUnknownMetaKeys = (meta: Map) => - (cursorMap: ) -> cursor - (actions: , data: , meta: ) -> cursor */ -const createCursorStore = (...args: {}[]) => { +function createCursorStore(...args: {}[]) { const { actions, data, meta } = args.length === 1 ? jsToMap(args[0]).toObject() @@ -71,15 +73,18 @@ const createCursorStore = (...args: {}[]) => { data: jsToMap(data), meta: jsToMap(meta).update(filterUnknownMetaKeys), }) as CursorStore; -}; +} -const hasAction = (store: CursorStore, action: string) => store.hasIn(['actions', action]); +function hasAction(store: CursorStore, action: string) { + return store.hasIn(['actions', action]); +} -const getActionHandlers = (store: CursorStore, handler: ActionHandler) => - store +function getActionHandlers(store: CursorStore, handler: ActionHandler) { + return store .get('actions', Set()) .toMap() .map(action => handler(action as string)); +} // The cursor logic is entirely functional, so this class simply // provides a chainable interface diff --git a/packages/netlify-cms-lib-util/src/__tests__/backendUtil.spec.js b/packages/netlify-cms-lib-util/src/__tests__/backendUtil.spec.js index 431c58a7..f9deeb87 100644 --- a/packages/netlify-cms-lib-util/src/__tests__/backendUtil.spec.js +++ b/packages/netlify-cms-lib-util/src/__tests__/backendUtil.spec.js @@ -21,17 +21,20 @@ describe('parseLinkHeader', () => { }); describe('getAllResponses', () => { - const generatePulls = length => { + function generatePulls(length) { return Array.from({ length }, (_, id) => { return { id: id + 1, number: `134${id}`, state: 'open' }; }); - }; + } function createLinkHeaders({ page, pageCount }) { const pageNum = parseInt(page, 10); const pageCountNum = parseInt(pageCount, 10); const url = 'https://api.github.com/pulls'; - const link = linkPage => `<${url}?page=${linkPage}>`; + + function link(linkPage) { + return `<${url}?page=${linkPage}>`; + } const linkHeader = oneLine` ${pageNum === 1 ? '' : `${link(1)}; rel="first",`} diff --git a/packages/netlify-cms-lib-util/src/asyncLock.ts b/packages/netlify-cms-lib-util/src/asyncLock.ts index 4cb61031..bb0d577d 100644 --- a/packages/netlify-cms-lib-util/src/asyncLock.ts +++ b/packages/netlify-cms-lib-util/src/asyncLock.ts @@ -2,10 +2,10 @@ import semaphore from 'semaphore'; export type AsyncLock = { release: () => void; acquire: () => Promise }; -export const asyncLock = (): AsyncLock => { +export function asyncLock(): AsyncLock { let lock = semaphore(1); - const acquire = (timeout = 15000) => { + function acquire(timeout = 15000) { const promise = new Promise(resolve => { // this makes sure a caller doesn't gets stuck forever awaiting on the lock const timeoutId = setTimeout(() => { @@ -21,9 +21,9 @@ export const asyncLock = (): AsyncLock => { }); return promise; - }; + } - const release = () => { + function release() { try { // suppress too many calls to leave error lock.leave(); @@ -37,7 +37,7 @@ export const asyncLock = (): AsyncLock => { lock = semaphore(1); } } - }; + } return { acquire, release }; -}; +} diff --git a/packages/netlify-cms-lib-util/src/backendUtil.ts b/packages/netlify-cms-lib-util/src/backendUtil.ts index 9a92e9af..3778686c 100644 --- a/packages/netlify-cms-lib-util/src/backendUtil.ts +++ b/packages/netlify-cms-lib-util/src/backendUtil.ts @@ -6,20 +6,22 @@ import APIError from './APIError'; type Formatter = (res: Response) => Promise; -export const filterByExtension = (file: { path: string }, extension: string) => { +export function filterByExtension(file: { path: string }, extension: string) { const path = file?.path || ''; return path.endsWith(extension.startsWith('.') ? extension : `.${extension}`); -}; +} -const catchFormatErrors = (format: string, formatter: Formatter) => (res: Response) => { - try { - return formatter(res); - } catch (err) { - throw new Error( - `Response cannot be parsed into the expected format (${format}): ${err.message}`, - ); - } -}; +function catchFormatErrors(format: string, formatter: Formatter) { + return (res: Response) => { + try { + return formatter(res); + } catch (err) { + throw new Error( + `Response cannot be parsed into the expected format (${format}): ${err.message}`, + ); + } + }; +} const responseFormatters = fromJS({ json: async (res: Response) => { @@ -36,10 +38,10 @@ const responseFormatters = fromJS({ catchFormatErrors(format, formatter), ]); -export const parseResponse = async ( +export async function parseResponse( res: Response, { expectingOk = true, format = 'text', apiName = '' }, -) => { +) { let body; try { const formatter = responseFormatters.get(format, false); @@ -56,15 +58,17 @@ export const parseResponse = async ( throw new APIError(isJSON && message ? message : body, res.status, apiName); } return body; -}; +} -export const responseParser = (options: { +export function responseParser(options: { expectingOk?: boolean; format: string; apiName: string; -}) => (res: Response) => parseResponse(res, options); +}) { + return (res: Response) => parseResponse(res, options); +} -export const parseLinkHeader = (header: string | null) => { +export function parseLinkHeader(header: string | null) { if (!header) { return {}; } @@ -80,14 +84,14 @@ export const parseLinkHeader = (header: string | null) => { ]), fromPairs, ])(header); -}; +} -export const getAllResponses = async ( +export async function getAllResponses( url: string, options: { headers?: {} } = {}, linkHeaderRelName: string, nextUrlProcessor: (url: string) => string, -) => { +) { const maxResponses = 30; let responseCount = 1; @@ -107,9 +111,9 @@ export const getAllResponses = async ( } return pageResponses; -}; +} -export const getPathDepth = (path: string) => { +export function getPathDepth(path: string) { const depth = path.split('/').length; return depth; -}; +} diff --git a/packages/netlify-cms-lib-util/src/git-lfs.ts b/packages/netlify-cms-lib-util/src/git-lfs.ts index 9834702f..f8ed2d2e 100644 --- a/packages/netlify-cms-lib-util/src/git-lfs.ts +++ b/packages/netlify-cms-lib-util/src/git-lfs.ts @@ -10,9 +10,18 @@ export interface PointerFile { sha: string; } -const splitIntoLines = (str: string) => str.split('\n'); -const splitIntoWords = (str: string) => str.split(/\s+/g); -const isNonEmptyString = (str: string) => str !== ''; +function splitIntoLines(str: string) { + return str.split('\n'); +} + +function splitIntoWords(str: string) { + return str.split(/\s+/g); +} + +function isNonEmptyString(str: string) { + return str !== ''; +} + const withoutEmptyLines = flow([map((str: string) => str.trim()), filter(isNonEmptyString)]); export const parsePointerFile: (data: string) => PointerFile = flow([ splitIntoLines, @@ -29,9 +38,11 @@ export const parsePointerFile: (data: string) => PointerFile = flow([ // // .gitattributes file parsing -const removeGitAttributesCommentsFromLine = (line: string) => line.split('#')[0]; +function removeGitAttributesCommentsFromLine(line: string) { + return line.split('#')[0]; +} -const parseGitPatternAttribute = (attributeString: string) => { +function parseGitPatternAttribute(attributeString: string) { // There are three kinds of attribute settings: // - a key=val pair sets an attribute to a specific value // - a key without a value and a leading hyphen sets an attribute to false @@ -44,7 +55,7 @@ const parseGitPatternAttribute = (attributeString: string) => { return [attributeString.slice(1), false]; } return [attributeString, true]; -}; +} const parseGitPatternAttributes = flow([map(parseGitPatternAttribute), fromPairs]); @@ -69,11 +80,13 @@ export const getLargeMediaPatternsFromGitAttributesFile = flow([ map(([pattern]) => pattern), ]); -export const createPointerFile = ({ size, sha }: PointerFile) => `\ +export function createPointerFile({ size, sha }: PointerFile) { + return `\ version https://git-lfs.github.com/spec/v1 oid sha256:${sha} size ${size} `; +} export async function getPointerFileForMediaFileObj( client: { uploadResource: (pointer: PointerFile, resource: Blob) => Promise }, diff --git a/packages/netlify-cms-lib-util/src/implementation.ts b/packages/netlify-cms-lib-util/src/implementation.ts index 350d53a4..14cf7e02 100644 --- a/packages/netlify-cms-lib-util/src/implementation.ts +++ b/packages/netlify-cms-lib-util/src/implementation.ts @@ -200,12 +200,12 @@ type ReadFile = ( type ReadFileMetadata = (path: string, id: string | null | undefined) => Promise; -const fetchFiles = async ( +async function fetchFiles( files: ImplementationFile[], readFile: ReadFile, readFileMetadata: ReadFileMetadata, apiName: string, -) => { +) { const sem = semaphore(MAX_CONCURRENT_DOWNLOADS); const promises = [] as Promise[]; files.forEach(file => { @@ -231,28 +231,28 @@ const fetchFiles = async ( return Promise.all(promises).then(loadedEntries => loadedEntries.filter(loadedEntry => !(loadedEntry as { error: boolean }).error), ) as Promise; -}; +} -export const entriesByFolder = async ( +export async function entriesByFolder( listFiles: () => Promise, readFile: ReadFile, readFileMetadata: ReadFileMetadata, apiName: string, -) => { +) { const files = await listFiles(); return fetchFiles(files, readFile, readFileMetadata, apiName); -}; +} -export const entriesByFiles = async ( +export async function entriesByFiles( files: ImplementationFile[], readFile: ReadFile, readFileMetadata: ReadFileMetadata, apiName: string, -) => { +) { return fetchFiles(files, readFile, readFileMetadata, apiName); -}; +} -export const unpublishedEntries = async (listEntriesKeys: () => Promise) => { +export async function unpublishedEntries(listEntriesKeys: () => Promise) { try { const keys = await listEntriesKeys(); return keys; @@ -262,14 +262,14 @@ export const unpublishedEntries = async (listEntriesKeys: () => Promise { +export function blobToFileObj(name: string, blob: Blob) { const options = name.match(/.svg$/) ? { type: 'image/svg+xml' } : {}; return new File([blob], name, options); -}; +} -export const getMediaAsBlob = async (path: string, id: string | null, readFile: ReadFile) => { +export async function getMediaAsBlob(path: string, id: string | null, readFile: ReadFile) { let blob: Blob; if (path.match(/.svg$/)) { const text = (await readFile(path, id, { parseText: true })) as string; @@ -278,13 +278,13 @@ export const getMediaAsBlob = async (path: string, id: string | null, readFile: blob = (await readFile(path, id, { parseText: false })) as Blob; } return blob; -}; +} -export const getMediaDisplayURL = async ( +export async function getMediaDisplayURL( displayURL: DisplayURL, readFile: ReadFile, semaphore: Semaphore, -) => { +) { const { path, id } = displayURL as DisplayURLObject; return new Promise((resolve, reject) => semaphore.take(() => @@ -294,9 +294,9 @@ export const getMediaDisplayURL = async ( .finally(() => semaphore.leave()), ), ); -}; +} -export const runWithLock = async (lock: AsyncLock, func: Function, message: string) => { +export async function runWithLock(lock: AsyncLock, func: Function, message: string) { try { const acquired = await lock.acquire(); if (!acquired) { @@ -308,7 +308,7 @@ export const runWithLock = async (lock: AsyncLock, func: Function, message: stri } finally { lock.release(); } -}; +} const LOCAL_KEY = 'git.local'; @@ -324,9 +324,9 @@ type GetKeyArgs = { depth: number; }; -const getLocalKey = ({ branch, folder, extension, depth }: GetKeyArgs) => { +function getLocalKey({ branch, folder, extension, depth }: GetKeyArgs) { return `${LOCAL_KEY}.${branch}.${folder}.${extension}.${depth}`; -}; +} type PersistLocalTreeArgs = GetKeyArgs & { localForage: LocalForage; @@ -337,32 +337,32 @@ type GetLocalTreeArgs = GetKeyArgs & { localForage: LocalForage; }; -export const persistLocalTree = async ({ +export async function persistLocalTree({ localForage, localTree, branch, folder, extension, depth, -}: PersistLocalTreeArgs) => { +}: PersistLocalTreeArgs) { await localForage.setItem( getLocalKey({ branch, folder, extension, depth }), localTree, ); -}; +} -export const getLocalTree = async ({ +export async function getLocalTree({ localForage, branch, folder, extension, depth, -}: GetLocalTreeArgs) => { +}: GetLocalTreeArgs) { const localTree = await localForage.getItem( getLocalKey({ branch, folder, extension, depth }), ); return localTree; -}; +} type GetDiffFromLocalTreeMethods = { getDifferences: ( @@ -387,14 +387,14 @@ type GetDiffFromLocalTreeArgs = GetDiffFromLocalTreeMethods & { depth: number; }; -const getDiffFromLocalTree = async ({ +async function getDiffFromLocalTree({ branch, localTree, folder, getDifferences, filterFile, getFileId, -}: GetDiffFromLocalTreeArgs) => { +}: GetDiffFromLocalTreeArgs) { const diff = await getDifferences(branch.sha, localTree.head); const diffFiles = diff .filter(d => d.oldPath?.startsWith(folder) || d.newPath?.startsWith(folder)) @@ -441,7 +441,7 @@ const getDiffFromLocalTree = async ({ ); return diffFilesWithIds; -}; +} type AllEntriesByFolderArgs = GetKeyArgs & GetDiffFromLocalTreeMethods & { @@ -458,7 +458,7 @@ type AllEntriesByFolderArgs = GetKeyArgs & localForage: LocalForage; }; -export const allEntriesByFolder = async ({ +export async function allEntriesByFolder({ listAllFiles, readFile, readFileMetadata, @@ -473,8 +473,8 @@ export const allEntriesByFolder = async ({ getDifferences, getFileId, filterFile, -}: AllEntriesByFolderArgs) => { - const listAllFilesAndPersist = async () => { +}: AllEntriesByFolderArgs) { + async function listAllFilesAndPersist() { const files = await listAllFiles(folder, extension, depth); const branch = await getDefaultBranch(); await persistLocalTree({ @@ -489,9 +489,9 @@ export const allEntriesByFolder = async ({ folder, }); return files; - }; + } - const listFiles = async () => { + async function listFiles() { const localTree = await getLocalTree({ localForage, branch, folder, extension, depth }); if (localTree) { const branch = await getDefaultBranch(); @@ -526,8 +526,6 @@ export const allEntriesByFolder = async ({ // return local copy return localTree.files; } else { - // refresh local copy - const identity = (file: { path: string }) => file.path; const deleted = diff.reduce((acc, d) => { acc[d.path] = d.deleted; return acc; @@ -536,9 +534,9 @@ export const allEntriesByFolder = async ({ unionBy( diff.filter(d => !deleted[d.path]), localTree.files.filter(f => !deleted[f.path]), - identity, + file => file.path, ), - identity, + file => file.path, ); await persistLocalTree({ @@ -555,8 +553,8 @@ export const allEntriesByFolder = async ({ } else { return listAllFilesAndPersist(); } - }; + } const files = await listFiles(); return fetchFiles(files, readFile, readFileMetadata, apiName); -}; +} diff --git a/packages/netlify-cms-lib-util/src/path.ts b/packages/netlify-cms-lib-util/src/path.ts index 10a3bd2d..7d4caff0 100644 --- a/packages/netlify-cms-lib-util/src/path.ts +++ b/packages/netlify-cms-lib-util/src/path.ts @@ -1,5 +1,8 @@ const absolutePath = new RegExp('^(?:[a-z]+:)?//', 'i'); -const normalizePath = (path: string) => path.replace(/[\\/]+/g, '/'); + +function normalizePath(path: string) { + return path.replace(/[\\/]+/g, '/'); +} export function isAbsolutePath(path: string) { return absolutePath.test(path); diff --git a/packages/netlify-cms-lib-util/src/promise.ts b/packages/netlify-cms-lib-util/src/promise.ts index b9972b59..995d2e8f 100644 --- a/packages/netlify-cms-lib-util/src/promise.ts +++ b/packages/netlify-cms-lib-util/src/promise.ts @@ -1,14 +1,21 @@ import flow from 'lodash/flow'; -export const then = (fn: (r: T) => V) => (p: Promise) => Promise.resolve(p).then(fn); +export function then(fn: (r: T) => V) { + return (p: Promise) => Promise.resolve(p).then(fn); +} const filterPromiseSymbol = Symbol('filterPromiseSymbol'); -export const onlySuccessfulPromises = (promises: Promise[]) => { +export function onlySuccessfulPromises(promises: Promise[]) { return Promise.all(promises.map(p => p.catch(() => filterPromiseSymbol))).then(results => results.filter(result => result !== filterPromiseSymbol), ); -}; +} -const wrapFlowAsync = (fn: Function) => async (arg: unknown) => fn(await arg); -export const flowAsync = (fns: Function[]) => flow(fns.map(fn => wrapFlowAsync(fn))); +function wrapFlowAsync(fn: Function) { + return async (arg: unknown) => fn(await arg); +} + +export function flowAsync(fns: Function[]) { + return flow(fns.map(fn => wrapFlowAsync(fn))); +} diff --git a/packages/netlify-cms-lib-util/src/unsentRequest.js b/packages/netlify-cms-lib-util/src/unsentRequest.js index 3daa50ef..a877c437 100644 --- a/packages/netlify-cms-lib-util/src/unsentRequest.js +++ b/packages/netlify-cms-lib-util/src/unsentRequest.js @@ -3,15 +3,16 @@ import curry from 'lodash/curry'; import flow from 'lodash/flow'; import isString from 'lodash/isString'; -const isAbortControllerSupported = () => { +function isAbortControllerSupported() { if (typeof window !== 'undefined') { return !!window.AbortController; } return false; -}; +} const timeout = 60; -const fetchWithTimeout = (input, init) => { + +function fetchWithTimeout(input, init) { if ((init && init.signal) || !isAbortControllerSupported()) { return fetch(input, init); } @@ -28,42 +29,47 @@ const fetchWithTimeout = (input, init) => { } throw e; }); -}; +} -const decodeParams = paramsString => - List(paramsString.split('&')) +function decodeParams(paramsString) { + return List(paramsString.split('&')) .map(s => List(s.split('=')).map(decodeURIComponent)) .update(Map); +} -const fromURL = wholeURL => { +function fromURL(wholeURL) { const [url, allParamsString] = wholeURL.split('?'); return Map({ url, ...(allParamsString ? { params: decodeParams(allParamsString) } : {}) }); -}; +} -const fromFetchArguments = (wholeURL, options) => { +function fromFetchArguments(wholeURL, options) { return fromURL(wholeURL).merge( (options ? fromJS(options) : Map()).remove('url').remove('params'), ); -}; +} -const encodeParams = params => - params +function encodeParams(params) { + return params .entrySeq() .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) .join('&'); +} -const toURL = req => - `${req.get('url')}${req.get('params') ? `?${encodeParams(req.get('params'))}` : ''}`; +function toURL(req) { + return `${req.get('url')}${req.get('params') ? `?${encodeParams(req.get('params'))}` : ''}`; +} -const toFetchArguments = req => [ - toURL(req), - req - .remove('url') - .remove('params') - .toJS(), -]; +function toFetchArguments(req) { + return [ + toURL(req), + req + .remove('url') + .remove('params') + .toJS(), + ]; +} -const maybeRequestArg = req => { +function maybeRequestArg(req) { if (isString(req)) { return fromURL(req); } @@ -71,9 +77,15 @@ const maybeRequestArg = req => { return fromJS(req); } return Map(); -}; -const ensureRequestArg = func => req => func(maybeRequestArg(req)); -const ensureRequestArg2 = func => (arg, req) => func(arg, maybeRequestArg(req)); +} + +function ensureRequestArg(func) { + return req => func(maybeRequestArg(req)); +} + +function ensureRequestArg2(func) { + return (arg, req) => func(arg, maybeRequestArg(req)); +} // This actually performs the built request object const performRequest = ensureRequestArg(req => { @@ -84,9 +96,14 @@ const performRequest = ensureRequestArg(req => { // Each of the following functions takes options and returns another // function that performs the requested action on a request. const getCurriedRequestProcessor = flow([ensureRequestArg2, curry]); -const getPropSetFunction = path => getCurriedRequestProcessor((val, req) => req.setIn(path, val)); -const getPropMergeFunction = path => - getCurriedRequestProcessor((obj, req) => req.updateIn(path, (p = Map()) => p.merge(obj))); + +function getPropSetFunction(path) { + return getCurriedRequestProcessor((val, req) => req.setIn(path, val)); +} + +function getPropMergeFunction(path) { + return getCurriedRequestProcessor((obj, req) => req.updateIn(path, (p = Map()) => p.merge(obj))); +} const withMethod = getPropSetFunction(['method']); const withBody = getPropSetFunction(['body']); diff --git a/packages/netlify-cms-lib-widgets/src/stringTemplate.ts b/packages/netlify-cms-lib-widgets/src/stringTemplate.ts index ad485f28..9671a233 100644 --- a/packages/netlify-cms-lib-widgets/src/stringTemplate.ts +++ b/packages/netlify-cms-lib-widgets/src/stringTemplate.ts @@ -48,7 +48,7 @@ export function parseDateFromEntry(entry: Map, dateFieldName?: export const SLUG_MISSING_REQUIRED_DATE = 'SLUG_MISSING_REQUIRED_DATE'; -export const keyToPathArray = (key?: string) => { +export function keyToPathArray(key?: string) { if (!key) { return []; } @@ -72,9 +72,9 @@ export const keyToPathArray = (key?: string) => { parts.push(currentStr.join(separator)); } return parts; -}; +} -export const expandPath = ({ +export function expandPath({ data, path, paths = [], @@ -82,7 +82,7 @@ export const expandPath = ({ data: Record; path: string; paths?: string[]; -}) => { +}) { if (path.endsWith('.*')) { path = path + '.'; } @@ -107,7 +107,7 @@ export const expandPath = ({ } return paths; -}; +} // Allow `fields.` prefix in placeholder to override built in replacements // like "slug" and "year" with values from fields of the same name. @@ -210,11 +210,7 @@ export function extractTemplateVars(template: string) { * eg: `addFileTemplateFields('foo/bar/baz.ext', fields, 'foo')` * will result in: `{ dirname: 'bar', filename: 'baz', extension: 'ext' }` */ -export const addFileTemplateFields = ( - entryPath: string, - fields: Map, - folder = '', -) => { +export function addFileTemplateFields(entryPath: string, fields: Map, folder = '') { if (!entryPath) { return fields; } @@ -229,4 +225,4 @@ export const addFileTemplateFields = ( }); return fields; -}; +} diff --git a/packages/netlify-cms-lib-widgets/src/validations.ts b/packages/netlify-cms-lib-widgets/src/validations.ts index f194d55a..e6ae133a 100644 --- a/packages/netlify-cms-lib-widgets/src/validations.ts +++ b/packages/netlify-cms-lib-widgets/src/validations.ts @@ -1,22 +1,24 @@ import { isNumber } from 'lodash'; import { List } from 'immutable'; -export const validateMinMax = ( +export function validateMinMax( t: (key: string, options: unknown) => string, fieldLabel: string, value?: List, min?: number, max?: number, -) => { - const minMaxError = (messageKey: string) => ({ - type: 'RANGE', - message: t(`editor.editorControlPane.widget.${messageKey}`, { - fieldLabel, - minCount: min, - maxCount: max, - count: min, - }), - }); +) { + function minMaxError(messageKey: string) { + return { + type: 'RANGE', + message: t(`editor.editorControlPane.widget.${messageKey}`, { + fieldLabel, + minCount: min, + maxCount: max, + count: min, + }), + }; + } if ([min, max, value?.size].every(isNumber) && (value!.size < min! || value!.size > max!)) { return minMaxError(min === max ? 'rangeCountExact' : 'rangeCount'); @@ -25,4 +27,4 @@ export const validateMinMax = ( } else if (isNumber(max) && value?.size && value.size > max) { return minMaxError('rangeMax'); } -}; +} diff --git a/packages/netlify-cms-media-library-cloudinary/src/index.js b/packages/netlify-cms-media-library-cloudinary/src/index.js index 2ed3c096..bd1cd306 100644 --- a/packages/netlify-cms-media-library-cloudinary/src/index.js +++ b/packages/netlify-cms-media-library-cloudinary/src/index.js @@ -58,10 +58,10 @@ async function init({ options = {}, handleInsert } = {}) { await loadScript('https://media-library.cloudinary.com/global/all.js'); - const insertHandler = data => { + function insertHandler(data) { const assets = data.assets.map(asset => getAssetUrl(asset, resolvedOptions)); handleInsert(providedConfig.multiple || assets.length > 1 ? assets : assets[0]); - }; + } const mediaLibrary = window.cloudinary.createMediaLibrary(cloudinaryConfig, { insertHandler }); diff --git a/packages/netlify-cms-media-library-uploadcare/src/index.js b/packages/netlify-cms-media-library-uploadcare/src/index.js index 0463976c..ae35fafc 100644 --- a/packages/netlify-cms-media-library-uploadcare/src/index.js +++ b/packages/netlify-cms-media-library-uploadcare/src/index.js @@ -23,7 +23,11 @@ const defaultConfig = { */ function isFileGroup(files) { const basePatternString = `~${files.length}/nth/`; - const mapExpression = (val, idx) => new RegExp(`${basePatternString}${idx}/$`); + + function mapExpression(val, idx) { + return new RegExp(`${basePatternString}${idx}/$`); + } + const expressions = Array.from({ length: files.length }, mapExpression); return expressions.every(exp => files.some(url => exp.test(url))); } @@ -80,7 +84,7 @@ function openDialog({ files, config, handleInsert, settings = {} }) { ); } - const buildUrl = fileInfo => { + function buildUrl(fileInfo) { const { cdnUrl, name, isImage } = fileInfo; let url = @@ -92,7 +96,7 @@ function openDialog({ files, config, handleInsert, settings = {} }) { } return url; - }; + } uploadcare.openDialog(files, config).done(({ promise, files }) => { const isGroup = Boolean(files); diff --git a/packages/netlify-cms-proxy-server/src/logger.ts b/packages/netlify-cms-proxy-server/src/logger.ts index 47e16c26..b92fc710 100644 --- a/packages/netlify-cms-proxy-server/src/logger.ts +++ b/packages/netlify-cms-proxy-server/src/logger.ts @@ -6,10 +6,10 @@ type LogOptions = { level: string; }; -export const createLogger = ({ level }: LogOptions) => { +export function createLogger({ level }: LogOptions) { return winston.createLogger({ level, format: combine(colorize(), simple()), transports: [new winston.transports.Console()], }); -}; +} diff --git a/packages/netlify-cms-proxy-server/src/middlewares.ts b/packages/netlify-cms-proxy-server/src/middlewares.ts index 5dd97bbb..9a269b5c 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares.ts @@ -8,20 +8,20 @@ type Options = { logLevel?: string; }; -const createOptions = (options: Options) => { +function createOptions(options: Options) { return { logger: createLogger({ level: options.logLevel || 'info' }), }; -}; +} -export const registerLocalGit = async (app: express.Express, options: Options = {}) => { +export async function registerLocalGit(app: express.Express, options: Options = {}) { const opts = createOptions(options); registerCommonMiddlewares(app, opts); await localGit(app, opts); -}; +} -export const registerLocalFs = async (app: express.Express, options: Options = {}) => { +export async function registerLocalFs(app: express.Express, options: Options = {}) { const opts = createOptions(options); registerCommonMiddlewares(app, opts); await localFs(app, opts); -}; +} diff --git a/packages/netlify-cms-proxy-server/src/middlewares/common/index.ts b/packages/netlify-cms-proxy-server/src/middlewares/common/index.ts index 724f2790..509d58fd 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/common/index.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/common/index.ts @@ -7,7 +7,7 @@ export type Options = { logger: winston.Logger; }; -export const registerCommonMiddlewares = (app: express.Express, options: Options) => { +export function registerCommonMiddlewares(app: express.Express, options: Options) { const { logger } = options; const stream = { write: (message: string) => { @@ -17,4 +17,4 @@ export const registerCommonMiddlewares = (app: express.Express, options: Options app.use(morgan('combined', { stream })); app.use(cors()); app.use(express.json({ limit: '50mb' })); -}; +} diff --git a/packages/netlify-cms-proxy-server/src/middlewares/joi/customValidators.ts b/packages/netlify-cms-proxy-server/src/middlewares/joi/customValidators.ts index 27db9aa4..bd12253c 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/joi/customValidators.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/joi/customValidators.ts @@ -1,8 +1,8 @@ import Joi from '@hapi/joi'; import path from 'path'; -export const pathTraversal = (repoPath: string) => - Joi.extend({ +export function pathTraversal(repoPath: string) { + return Joi.extend({ type: 'path', base: Joi.string().required(), messages: { @@ -15,3 +15,4 @@ export const pathTraversal = (repoPath: string) => } }, }).path(); +} diff --git a/packages/netlify-cms-proxy-server/src/middlewares/joi/index.spec.ts b/packages/netlify-cms-proxy-server/src/middlewares/joi/index.spec.ts index 0d42f0f6..8b6e050a 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/joi/index.spec.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/joi/index.spec.ts @@ -2,13 +2,13 @@ import { defaultSchema, joi } from '.'; import express from 'express'; import Joi from '@hapi/joi'; -const assetFailure = (result: Joi.ValidationResult, expectedMessage: string) => { +function assetFailure(result: Joi.ValidationResult, expectedMessage: string) { const { error } = result; expect(error).not.toBeNull(); expect(error!.details).toHaveLength(1); const message = error!.details.map(({ message }) => message)[0]; expect(message).toBe(expectedMessage); -}; +} const defaultParams = { branch: 'master', diff --git a/packages/netlify-cms-proxy-server/src/middlewares/joi/index.ts b/packages/netlify-cms-proxy-server/src/middlewares/joi/index.ts index c3976bdd..90f38140 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/joi/index.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/joi/index.ts @@ -29,7 +29,7 @@ const requiredBool = Joi.bool().required(); const collection = requiredString; const slug = requiredString; -export const defaultSchema = ({ path = requiredString } = {}) => { +export function defaultSchema({ path = requiredString } = {}) { const defaultParams = Joi.object({ branch: requiredString, }); @@ -234,19 +234,17 @@ export const defaultSchema = ({ path = requiredString } = {}) => { action: Joi.valid(...allowedActions).required(), params, }); -}; +} -export const joi = (schema: Joi.Schema) => ( - req: express.Request, - res: express.Response, - next: express.NextFunction, -) => { - const { error } = schema.validate(req.body, { allowUnknown: true }); - if (error) { - const { details } = error; - const message = details.map(i => i.message).join(','); - res.status(422).json({ error: message }); - } else { - next(); - } -}; +export function joi(schema: Joi.Schema) { + return (req: express.Request, res: express.Response, next: express.NextFunction) => { + const { error } = schema.validate(req.body, { allowUnknown: true }); + if (error) { + const { details } = error; + const message = details.map(i => i.message).join(','); + res.status(422).json({ error: message }); + } else { + next(); + } + }; +} diff --git a/packages/netlify-cms-proxy-server/src/middlewares/localFs/index.spec.ts b/packages/netlify-cms-proxy-server/src/middlewares/localFs/index.spec.ts index 24b20ac3..eac526c4 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/localFs/index.spec.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/localFs/index.spec.ts @@ -2,13 +2,13 @@ import Joi from '@hapi/joi'; import { getSchema } from '.'; -const assetFailure = (result: Joi.ValidationResult, expectedMessage: string) => { +function assetFailure(result: Joi.ValidationResult, expectedMessage: string) { const { error } = result; expect(error).not.toBeNull(); expect(error!.details).toHaveLength(1); const message = error!.details.map(({ message }) => message)[0]; expect(message).toBe(expectedMessage); -}; +} const defaultParams = { branch: 'master', diff --git a/packages/netlify-cms-proxy-server/src/middlewares/localFs/index.ts b/packages/netlify-cms-proxy-server/src/middlewares/localFs/index.ts index 2bbc760e..7f2f3a9e 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/localFs/index.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/localFs/index.ts @@ -23,7 +23,7 @@ type FsOptions = { logger: winston.Logger; }; -export const localFsMiddleware = ({ repoPath, logger }: FsOptions) => { +export function localFsMiddleware({ repoPath, logger }: FsOptions) { return async function(req: express.Request, res: express.Response) { try { const { body } = req; @@ -138,21 +138,21 @@ export const localFsMiddleware = ({ repoPath, logger }: FsOptions) => { res.status(500).json({ error: 'Unknown error' }); } }; -}; +} -export const getSchema = ({ repoPath }: { repoPath: string }) => { +export function getSchema({ repoPath }: { repoPath: string }) { const schema = defaultSchema({ path: pathTraversal(repoPath) }); return schema; -}; +} type Options = { logger: winston.Logger; }; -export const registerMiddleware = async (app: express.Express, options: Options) => { +export async function registerMiddleware(app: express.Express, options: Options) { const { logger } = options; const repoPath = path.resolve(process.env.GIT_REPO_DIRECTORY || process.cwd()); app.post('/api/v1', joi(getSchema({ repoPath }))); app.post('/api/v1', localFsMiddleware({ repoPath, logger })); logger.info(`Netlify CMS File System Proxy Server configured with ${repoPath}`); -}; +} diff --git a/packages/netlify-cms-proxy-server/src/middlewares/localGit/index.spec.ts b/packages/netlify-cms-proxy-server/src/middlewares/localGit/index.spec.ts index 8f4fd7ac..3f5701cf 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/localGit/index.spec.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/localGit/index.spec.ts @@ -1,18 +1,19 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import Joi from '@hapi/joi'; import express from 'express'; +import winston from 'winston'; import { validateRepo, getSchema, localGitMiddleware } from '.'; jest.mock('netlify-cms-lib-util', () => jest.fn()); jest.mock('simple-git/promise'); -const assetFailure = (result: Joi.ValidationResult, expectedMessage: string) => { +function assetFailure(result: Joi.ValidationResult, expectedMessage: string) { const { error } = result; expect(error).not.toBeNull(); expect(error!.details).toHaveLength(1); const message = error!.details.map(({ message }) => message)[0]; expect(message).toBe(expectedMessage); -}; +} const defaultParams = { branch: 'master', @@ -139,7 +140,7 @@ describe('localGitMiddleware', () => { }, } as express.Request; - await localGitMiddleware({ repoPath })(req, res); + await localGitMiddleware({ repoPath, logger: winston.createLogger() })(req, res); expect(status).toHaveBeenCalledTimes(1); expect(status).toHaveBeenCalledWith(422); diff --git a/packages/netlify-cms-proxy-server/src/middlewares/localGit/index.ts b/packages/netlify-cms-proxy-server/src/middlewares/localGit/index.ts index fc5ebcb1..e8837546 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/localGit/index.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/localGit/index.ts @@ -40,7 +40,7 @@ import { pathTraversal } from '../joi/customValidators'; import { listRepoFiles, writeFile, move, deleteFile, getUpdateDate } from '../utils/fs'; import { entriesFromFiles, readMediaFile } from '../utils/entries'; -const commit = async (git: simpleGit.SimpleGit, commitMessage: string) => { +async function commit(git: simpleGit.SimpleGit, commitMessage: string) { await git.add('.'); await git.commit(commitMessage, undefined, { // setting the value to a string passes name=value @@ -48,14 +48,14 @@ const commit = async (git: simpleGit.SimpleGit, commitMessage: string) => { '--no-verify': null, '--no-gpg-sign': null, }); -}; +} -const getCurrentBranch = async (git: simpleGit.SimpleGit) => { +async function getCurrentBranch(git: simpleGit.SimpleGit) { const currentBranch = await git.branchLocal().then(summary => summary.current); return currentBranch; -}; +} -const runOnBranch = async (git: simpleGit.SimpleGit, branch: string, func: () => Promise) => { +async function runOnBranch(git: simpleGit.SimpleGit, branch: string, func: () => Promise) { const currentBranch = await getCurrentBranch(git); try { if (currentBranch !== branch) { @@ -66,22 +66,24 @@ const runOnBranch = async (git: simpleGit.SimpleGit, branch: string, func: () } finally { await git.checkout(currentBranch); } -}; +} -const branchDescription = (branch: string) => `branch.${branch}.description`; +function branchDescription(branch: string) { + return `branch.${branch}.description`; +} type GitOptions = { repoPath: string; logger: winston.Logger; }; -const commitEntry = async ( +async function commitEntry( git: simpleGit.SimpleGit, repoPath: string, dataFiles: DataFile[], assets: Asset[], commitMessage: string, -) => { +) { // save entry content await Promise.all( dataFiles.map(dataFile => writeFile(path.join(repoPath, dataFile.path), dataFile.raw)), @@ -98,9 +100,9 @@ const commitEntry = async ( // commits files await commit(git, commitMessage); -}; +} -const rebase = async (git: simpleGit.SimpleGit, branch: string) => { +async function rebase(git: simpleGit.SimpleGit, branch: string) { const gpgSign = await git.raw(['config', 'commit.gpgsign']); try { if (gpgSign === 'true') { @@ -112,9 +114,9 @@ const rebase = async (git: simpleGit.SimpleGit, branch: string) => { await git.addConfig('commit.gpgsign', gpgSign); } } -}; +} -const merge = async (git: simpleGit.SimpleGit, from: string, to: string) => { +async function merge(git: simpleGit.SimpleGit, from: string, to: string) { const gpgSign = await git.raw(['config', 'commit.gpgsign']); try { if (gpgSign === 'true') { @@ -126,14 +128,14 @@ const merge = async (git: simpleGit.SimpleGit, from: string, to: string) => { await git.addConfig('commit.gpgsign', gpgSign); } } -}; +} -const isBranchExists = async (git: simpleGit.SimpleGit, branch: string) => { +async function isBranchExists(git: simpleGit.SimpleGit, branch: string) { const branchExists = await git.branchLocal().then(({ all }) => all.includes(branch)); return branchExists; -}; +} -const getDiffs = async (git: simpleGit.SimpleGit, source: string, dest: string) => { +async function getDiffs(git: simpleGit.SimpleGit, source: string, dest: string) { const rawDiff = await git.diff([source, dest]); const diffs = parse(rawDiff).map(d => { const oldPath = d.oldPath?.replace(/b\//, '') || ''; @@ -150,22 +152,22 @@ const getDiffs = async (git: simpleGit.SimpleGit, source: string, dest: string) }; }); return diffs; -}; +} -export const validateRepo = async ({ repoPath }: { repoPath: string }) => { +export async function validateRepo({ repoPath }: { repoPath: string }) { const git = simpleGit(repoPath).silent(false); const isRepo = await git.checkIsRepo(); if (!isRepo) { throw Error(`${repoPath} is not a valid git repository`); } -}; +} -export const getSchema = ({ repoPath }: { repoPath: string }) => { +export function getSchema({ repoPath }: { repoPath: string }) { const schema = defaultSchema({ path: pathTraversal(repoPath) }); return schema; -}; +} -export const localGitMiddleware = ({ repoPath, logger }: GitOptions) => { +export function localGitMiddleware({ repoPath, logger }: GitOptions) { const git = simpleGit(repoPath).silent(false); // we can only perform a single git operation at any given time @@ -443,17 +445,17 @@ export const localGitMiddleware = ({ repoPath, logger }: GitOptions) => { release && release(); } }; -}; +} type Options = { logger: winston.Logger; }; -export const registerMiddleware = async (app: express.Express, options: Options) => { +export async function registerMiddleware(app: express.Express, options: Options) { const { logger } = options; const repoPath = path.resolve(process.env.GIT_REPO_DIRECTORY || process.cwd()); await validateRepo({ repoPath }); app.post('/api/v1', joi(getSchema({ repoPath }))); app.post('/api/v1', localGitMiddleware({ repoPath, logger })); logger.info(`Netlify CMS Git Proxy Server configured with ${repoPath}`); -}; +} diff --git a/packages/netlify-cms-proxy-server/src/middlewares/utils/entries.ts b/packages/netlify-cms-proxy-server/src/middlewares/utils/entries.ts index caa2fcbf..a839dc3c 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/utils/entries.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/utils/entries.ts @@ -2,20 +2,22 @@ import crypto from 'crypto'; import path from 'path'; import { promises as fs } from 'fs'; -const sha256 = (buffer: Buffer) => { +function sha256(buffer: Buffer) { return crypto .createHash('sha256') .update(buffer) .digest('hex'); -}; +} // normalize windows os path format -const normalizePath = (path: string) => path.replace(/\\/g, '/'); +function normalizePath(path: string) { + return path.replace(/\\/g, '/'); +} -export const entriesFromFiles = async ( +export async function entriesFromFiles( repoPath: string, files: { path: string; label?: string }[], -) => { +) { return Promise.all( files.map(async file => { try { @@ -32,9 +34,9 @@ export const entriesFromFiles = async ( } }), ); -}; +} -export const readMediaFile = async (repoPath: string, file: string) => { +export async function readMediaFile(repoPath: string, file: string) { const encoding = 'base64'; const buffer = await fs.readFile(path.join(repoPath, file)); const id = sha256(buffer); @@ -46,4 +48,4 @@ export const readMediaFile = async (repoPath: string, file: string) => { path: normalizePath(file), name: path.basename(file), }; -}; +} diff --git a/packages/netlify-cms-proxy-server/src/middlewares/utils/fs.ts b/packages/netlify-cms-proxy-server/src/middlewares/utils/fs.ts index 476a0724..73f4f6cc 100644 --- a/packages/netlify-cms-proxy-server/src/middlewares/utils/fs.ts +++ b/packages/netlify-cms-proxy-server/src/middlewares/utils/fs.ts @@ -1,7 +1,7 @@ import path from 'path'; import { promises as fs } from 'fs'; -const listFiles = async (dir: string, extension: string, depth: number): Promise => { +async function listFiles(dir: string, extension: string, depth: number): Promise { if (depth <= 0) { return []; } @@ -20,33 +20,33 @@ const listFiles = async (dir: string, extension: string, depth: number): Promise } catch (e) { return []; } -}; +} -export const listRepoFiles = async ( +export async function listRepoFiles( repoPath: string, folder: string, extension: string, depth: number, -) => { +) { const files = await listFiles(path.join(repoPath, folder), extension, depth); return files.map(f => f.substr(repoPath.length + 1)); -}; +} -export const writeFile = async (filePath: string, content: Buffer | string) => { +export async function writeFile(filePath: string, content: Buffer | string) { await fs.mkdir(path.dirname(filePath), { recursive: true }); await fs.writeFile(filePath, content); -}; +} -export const deleteFile = async (repoPath: string, filePath: string) => { +export async function deleteFile(repoPath: string, filePath: string) { await fs.unlink(path.join(repoPath, filePath)).catch(() => undefined); -}; +} -const moveFile = async (from: string, to: string) => { +async function moveFile(from: string, to: string) { await fs.mkdir(path.dirname(to), { recursive: true }); await fs.rename(from, to); -}; +} -export const move = async (from: string, to: string) => { +export async function move(from: string, to: string) { // move file await moveFile(from, to); @@ -55,11 +55,11 @@ export const move = async (from: string, to: string) => { const destDir = path.dirname(to); const allFiles = await listFiles(sourceDir, '', 100); await Promise.all(allFiles.map(file => moveFile(file, file.replace(sourceDir, destDir)))); -}; +} -export const getUpdateDate = async (repoPath: string, filePath: string) => { +export async function getUpdateDate(repoPath: string, filePath: string) { return fs .stat(path.join(repoPath, filePath)) .then(stat => stat.mtime) .catch(() => new Date()); -}; +} diff --git a/packages/netlify-cms-ui-default/src/AuthenticationPage.js b/packages/netlify-cms-ui-default/src/AuthenticationPage.js index 7ec4bcee..3c2bb551 100644 --- a/packages/netlify-cms-ui-default/src/AuthenticationPage.js +++ b/packages/netlify-cms-ui-default/src/AuthenticationPage.js @@ -30,20 +30,20 @@ const NetlifyCreditIcon = styled(Icon)` bottom: 10px; `; -const CustomLogoIcon = ({ url }) => { +function CustomLogoIcon({ url }) { return ( Logo ); -}; +} -const renderPageLogo = logoUrl => { +function renderPageLogo(logoUrl) { if (logoUrl) { return ; } return ; -}; +} const LoginButton = styled.button` ${buttons.button}; @@ -61,7 +61,7 @@ const LoginButton = styled.button` position: relative; `; -const AuthenticationPage = ({ +function AuthenticationPage({ onLogin, loginDisabled, loginErrorMessage, @@ -70,7 +70,7 @@ const AuthenticationPage = ({ logoUrl, siteUrl, t, -}) => { +}) { return ( {renderPageLogo(logoUrl)} @@ -85,7 +85,7 @@ const AuthenticationPage = ({ {logoUrl ? : null} ); -}; +} AuthenticationPage.propTypes = { onLogin: PropTypes.func, diff --git a/packages/netlify-cms-ui-default/src/Dropdown.js b/packages/netlify-cms-ui-default/src/Dropdown.js index e1b7cc47..01b6d0fd 100644 --- a/packages/netlify-cms-ui-default/src/Dropdown.js +++ b/packages/netlify-cms-ui-default/src/Dropdown.js @@ -48,26 +48,28 @@ const DropdownList = styled.ul` `}; `; -const StyledMenuItem = ({ isActive, isCheckedItem = false, ...props }) => ( - -); +function StyledMenuItem({ isActive, isCheckedItem = false, ...props }) { + return ( + + ); +} const MenuItemIconContainer = styled.div` flex: 1 0 32px; @@ -76,7 +78,7 @@ const MenuItemIconContainer = styled.div` top: ${props => (props.iconSmall ? '0' : '2px')}; `; -const Dropdown = ({ +function Dropdown({ closeOnSelection = true, renderButton, dropdownWidth = 'auto', @@ -84,7 +86,7 @@ const Dropdown = ({ dropdownTopOverlap = '0', className, children, -}) => { +}) { return ( ); -}; +} Dropdown.propTypes = { renderButton: PropTypes.func.isRequired, @@ -110,16 +112,18 @@ Dropdown.propTypes = { children: PropTypes.node, }; -const DropdownItem = ({ label, icon, iconDirection, iconSmall, isActive, onClick, className }) => ( - - {label} - {icon ? ( - - - - ) : null} - -); +function DropdownItem({ label, icon, iconDirection, iconSmall, isActive, onClick, className }) { + return ( + + {label} + {icon ? ( + + + + ) : null} + + ); +} DropdownItem.propTypes = { label: PropTypes.string, @@ -129,26 +133,28 @@ DropdownItem.propTypes = { className: PropTypes.string, }; -const StyledDropdownCheckbox = ({ checked, id }) => ( - -); +function StyledDropdownCheckbox({ checked, id }) { + return ( + + ); +} -const DropdownCheckedItem = ({ label, id, checked, onClick }) => { +function DropdownCheckedItem({ label, id, checked, onClick }) { return ( {label} ); -}; +} DropdownCheckedItem.propTypes = { label: PropTypes.string.isRequired, diff --git a/packages/netlify-cms-ui-default/src/FieldLabel.js b/packages/netlify-cms-ui-default/src/FieldLabel.js index 665d790e..e8d1a716 100644 --- a/packages/netlify-cms-ui-default/src/FieldLabel.js +++ b/packages/netlify-cms-ui-default/src/FieldLabel.js @@ -16,11 +16,11 @@ const stateColors = { }, }; -const getStateColors = ({ isActive, hasErrors }) => { +function getStateColors({ isActive, hasErrors }) { if (hasErrors) return stateColors.error; if (isActive) return stateColors.active; return stateColors.default; -}; +} const FieldLabel = styled.label` ${text.fieldLabel}; diff --git a/packages/netlify-cms-ui-default/src/Icon.js b/packages/netlify-cms-ui-default/src/Icon.js index cd8a8e36..0eb68c60 100644 --- a/packages/netlify-cms-ui-default/src/Icon.js +++ b/packages/netlify-cms-ui-default/src/Icon.js @@ -35,14 +35,14 @@ const IconWrapper = styled.span` * Returned value is a string of shape `${degrees}deg`, for use in a CSS * transform. */ -const getRotation = (iconDirection, newDirection) => { +function getRotation(iconDirection, newDirection) { if (!iconDirection || !newDirection) { return '0deg'; } const rotations = { right: 90, down: 180, left: 270, up: 360 }; const degrees = rotations[newDirection] - rotations[iconDirection]; return `${degrees}deg`; -}; +} const sizes = { xsmall: '12px', @@ -51,7 +51,7 @@ const sizes = { large: '32px', }; -const Icon = ({ type, direction, size = 'medium', className }) => { +function Icon({ type, direction, size = 'medium', className }) { const IconSvg = icons[type].image; return ( @@ -63,7 +63,7 @@ const Icon = ({ type, direction, size = 'medium', className }) => { ); -}; +} Icon.propTypes = { type: PropTypes.string.isRequired, diff --git a/packages/netlify-cms-ui-default/src/IconButton.js b/packages/netlify-cms-ui-default/src/IconButton.js index 05c2f005..29e6549c 100644 --- a/packages/netlify-cms-ui-default/src/IconButton.js +++ b/packages/netlify-cms-ui-default/src/IconButton.js @@ -22,16 +22,18 @@ const ButtonRound = styled.button` padding: 0; `; -const IconButton = ({ size, isActive, type, onClick, className, title }) => ( - - - -); +function IconButton({ size, isActive, type, onClick, className, title }) { + return ( + + + + ); +} export default IconButton; diff --git a/packages/netlify-cms-ui-default/src/ListItemTopBar.js b/packages/netlify-cms-ui-default/src/ListItemTopBar.js index 46ab862a..055c9461 100644 --- a/packages/netlify-cms-ui-default/src/ListItemTopBar.js +++ b/packages/netlify-cms-ui-default/src/ListItemTopBar.js @@ -34,30 +34,32 @@ const DragIconContainer = styled(TopBarButtonSpan)` cursor: move; `; -const DragHandle = ({ dragHandleHOC }) => { +function DragHandle({ dragHandleHOC }) { const Handle = dragHandleHOC(() => ( )); return ; -}; +} -const ListItemTopBar = ({ className, collapsed, onCollapseToggle, onRemove, dragHandleHOC }) => ( - - {onCollapseToggle ? ( - - - - ) : null} - {dragHandleHOC ? : null} - {onRemove ? ( - - - - ) : null} - -); +function ListItemTopBar({ className, collapsed, onCollapseToggle, onRemove, dragHandleHOC }) { + return ( + + {onCollapseToggle ? ( + + + + ) : null} + {dragHandleHOC ? : null} + {onRemove ? ( + + + + ) : null} + + ); +} ListItemTopBar.propTypes = { className: PropTypes.string, diff --git a/packages/netlify-cms-ui-default/src/Toggle.js b/packages/netlify-cms-ui-default/src/Toggle.js index 1d17de60..ec9bdb97 100644 --- a/packages/netlify-cms-ui-default/src/Toggle.js +++ b/packages/netlify-cms-ui-default/src/Toggle.js @@ -44,7 +44,7 @@ const ToggleBackground = styled.span` background-color: ${colors.active}; `; -const Toggle = ({ +function Toggle({ id, active, onChange, @@ -54,26 +54,28 @@ const Toggle = ({ Container = ToggleContainer, Background = ToggleBackground, Handle = ToggleHandle, -}) => ( - - {({ on, getTogglerProps }) => ( - - - - - )} - -); +}) { + return ( + + {({ on, getTogglerProps }) => ( + + + + + )} + + ); +} Toggle.propTypes = { id: PropTypes.string, diff --git a/packages/netlify-cms-ui-default/src/styles.js b/packages/netlify-cms-ui-default/src/styles.js index 900c22c5..098d1079 100644 --- a/packages/netlify-cms-ui-default/src/styles.js +++ b/packages/netlify-cms-ui-default/src/styles.js @@ -414,93 +414,95 @@ const zIndex = { zIndex99999: 99999, }; -const GlobalStyles = () => ( - -); + textarea { + resize: none; + } + `} + /> + ); +} export { fonts, diff --git a/packages/netlify-cms-widget-boolean/src/BooleanControl.js b/packages/netlify-cms-widget-boolean/src/BooleanControl.js index 0c0cb27a..67d9a12e 100644 --- a/packages/netlify-cms-widget-boolean/src/BooleanControl.js +++ b/packages/netlify-cms-widget-boolean/src/BooleanControl.js @@ -4,14 +4,16 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { css } from '@emotion/core'; import { Toggle, ToggleBackground, colors } from 'netlify-cms-ui-default'; -const BooleanBackground = ({ isActive, ...props }) => ( - -); +function BooleanBackground({ isActive, ...props }) { + return ( + + ); +} export default class BooleanControl extends React.Component { render() { diff --git a/packages/netlify-cms-widget-boolean/src/index.js b/packages/netlify-cms-widget-boolean/src/index.js index b90dd3ed..54429a9a 100644 --- a/packages/netlify-cms-widget-boolean/src/index.js +++ b/packages/netlify-cms-widget-boolean/src/index.js @@ -1,10 +1,12 @@ import controlComponent from './BooleanControl'; -const Widget = (opts = {}) => ({ - name: 'boolean', - controlComponent, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'boolean', + controlComponent, + ...opts, + }; +} export const NetlifyCmsWidgetBoolean = { Widget, controlComponent }; export default NetlifyCmsWidgetBoolean; diff --git a/packages/netlify-cms-widget-code/src/CodePreview.js b/packages/netlify-cms-widget-code/src/CodePreview.js index 78bb85f6..46da0983 100644 --- a/packages/netlify-cms-widget-code/src/CodePreview.js +++ b/packages/netlify-cms-widget-code/src/CodePreview.js @@ -4,7 +4,7 @@ import { Map } from 'immutable'; import { isString } from 'lodash'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const toValue = (value, field) => { +function toValue(value, field) { if (isString(value)) { return value; } @@ -12,15 +12,17 @@ const toValue = (value, field) => { return value.get(field.getIn(['keys', 'code'], 'code'), ''); } return ''; -}; +} -const CodePreview = props => ( - -
-      {toValue(props.value, props.field)}
-    
-
-); +function CodePreview(props) { + return ( + +
+        {toValue(props.value, props.field)}
+      
+
+ ); +} CodePreview.propTypes = { value: PropTypes.node, diff --git a/packages/netlify-cms-widget-code/src/SettingsButton.js b/packages/netlify-cms-widget-code/src/SettingsButton.js index a4260f1c..a7a42db6 100644 --- a/packages/netlify-cms-widget-code/src/SettingsButton.js +++ b/packages/netlify-cms-widget-code/src/SettingsButton.js @@ -22,10 +22,12 @@ const StyledSettingsButton = styled.button` } `; -const SettingsButton = ({ showClose, onClick }) => ( - - - -); +function SettingsButton({ showClose, onClick }) { + return ( + + + + ); +} export default SettingsButton; diff --git a/packages/netlify-cms-widget-code/src/SettingsPane.js b/packages/netlify-cms-widget-code/src/SettingsPane.js index 33ca23db..04df5f6c 100644 --- a/packages/netlify-cms-widget-code/src/SettingsPane.js +++ b/packages/netlify-cms-widget-code/src/SettingsPane.js @@ -38,20 +38,22 @@ const SettingsSectionTitle = styled.h3` } `; -const SettingsSelect = ({ value, options, onChange, forID, type, autoFocus }) => ( - onChange(opt.value)} + menuPlacement="auto" + captureMenuScroll={false} + autoFocus={autoFocus} + /> + ); +} -const SettingsPane = ({ +function SettingsPane({ hideSettings, forID, modes, @@ -64,48 +66,50 @@ const SettingsPane = ({ onChangeLang, onChangeTheme, onChangeKeyMap, -}) => ( - isHotkey('esc', e) && hideSettings()}> - - {allowLanguageSelection && ( - <> - Field Settings - Mode - - - )} - <> - Global Settings - {themes && ( +}) { + return ( + isHotkey('esc', e) && hideSettings()}> + + {allowLanguageSelection && ( <> - Theme + Field Settings + Mode ({ value: t, label: t }))} - onChange={onChangeTheme} - autoFocus={!allowLanguageSelection} + value={mode} + options={modes} + onChange={onChangeLang} + autoFocus /> )} - KeyMap - - - -); + <> + Global Settings + {themes && ( + <> + Theme + ({ value: t, label: t }))} + onChange={onChangeTheme} + autoFocus={!allowLanguageSelection} + /> + + )} + KeyMap + + + + ); +} export default SettingsPane; diff --git a/packages/netlify-cms-widget-code/src/index.js b/packages/netlify-cms-widget-code/src/index.js index 05529ec3..0416867b 100644 --- a/packages/netlify-cms-widget-code/src/index.js +++ b/packages/netlify-cms-widget-code/src/index.js @@ -2,15 +2,17 @@ import controlComponent from './CodeControl'; import previewComponent from './CodePreview'; import schema from './schema'; -const Widget = (opts = {}) => ({ - name: 'code', - controlComponent, - previewComponent, - schema, - allowMapValue: true, - codeMirrorConfig: {}, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'code', + controlComponent, + previewComponent, + schema, + allowMapValue: true, + codeMirrorConfig: {}, + ...opts, + }; +} export const NetlifyCmsWidgetCode = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetCode; diff --git a/packages/netlify-cms-widget-colorstring/src/ColorControl.js b/packages/netlify-cms-widget-colorstring/src/ColorControl.js index 9f5ee416..ff500620 100644 --- a/packages/netlify-cms-widget-colorstring/src/ColorControl.js +++ b/packages/netlify-cms-widget-colorstring/src/ColorControl.js @@ -5,14 +5,16 @@ import ChromePicker from 'react-color'; import validateColor from 'validate-color'; import { zIndex } from 'netlify-cms-ui-default'; -const ClearIcon = () => ( - -); +function ClearIcon() { + return ( + + ); +} const ClearButton = styled.div` position: absolute; diff --git a/packages/netlify-cms-widget-colorstring/src/ColorPreview.js b/packages/netlify-cms-widget-colorstring/src/ColorPreview.js index bff43a4b..8ced4f59 100644 --- a/packages/netlify-cms-widget-colorstring/src/ColorPreview.js +++ b/packages/netlify-cms-widget-colorstring/src/ColorPreview.js @@ -2,7 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const ColorPreview = ({ value }) => {value}; +function ColorPreview({ value }) { + return {value}; +} ColorPreview.propTypes = { value: PropTypes.node, diff --git a/packages/netlify-cms-widget-colorstring/src/index.js b/packages/netlify-cms-widget-colorstring/src/index.js index 688afa3b..6e12670b 100644 --- a/packages/netlify-cms-widget-colorstring/src/index.js +++ b/packages/netlify-cms-widget-colorstring/src/index.js @@ -1,12 +1,14 @@ import controlComponent from './ColorControl'; import previewComponent from './ColorPreview'; -const Widget = (opts = {}) => ({ - name: 'color', - controlComponent, - previewComponent, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'color', + controlComponent, + previewComponent, + ...opts, + }; +} export const NetlifyCmsWidgetColorString = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetColorString; diff --git a/packages/netlify-cms-widget-date/src/DatePreview.js b/packages/netlify-cms-widget-date/src/DatePreview.js index 5ecd7098..6c97679f 100644 --- a/packages/netlify-cms-widget-date/src/DatePreview.js +++ b/packages/netlify-cms-widget-date/src/DatePreview.js @@ -2,9 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const DatePreview = ({ value }) => ( - {value ? value.toString() : null} -); +function DatePreview({ value }) { + return {value ? value.toString() : null}; +} DatePreview.propTypes = { value: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), diff --git a/packages/netlify-cms-widget-date/src/index.js b/packages/netlify-cms-widget-date/src/index.js index b28ca92b..4060a680 100644 --- a/packages/netlify-cms-widget-date/src/index.js +++ b/packages/netlify-cms-widget-date/src/index.js @@ -1,12 +1,14 @@ import controlComponent from './DateControl'; import previewComponent from './DatePreview'; -const Widget = (opts = {}) => ({ - name: 'date', - controlComponent, - previewComponent, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'date', + controlComponent, + previewComponent, + ...opts, + }; +} export const NetlifyCmsWidgetDate = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetDate; diff --git a/packages/netlify-cms-widget-datetime/src/DateTimeControl.js b/packages/netlify-cms-widget-datetime/src/DateTimeControl.js index 9cfec02d..01d0037b 100644 --- a/packages/netlify-cms-widget-datetime/src/DateTimeControl.js +++ b/packages/netlify-cms-widget-datetime/src/DateTimeControl.js @@ -7,7 +7,7 @@ import DateTime from 'react-datetime'; import moment from 'moment'; import { buttons } from 'netlify-cms-ui-default'; -const NowButton = ({ t, handleChange }) => { +function NowButton({ t, handleChange }) { return (
{
); -}; +} export default class DateTimeControl extends React.Component { static propTypes = { diff --git a/packages/netlify-cms-widget-datetime/src/DateTimePreview.js b/packages/netlify-cms-widget-datetime/src/DateTimePreview.js index 5ecd7098..6c97679f 100644 --- a/packages/netlify-cms-widget-datetime/src/DateTimePreview.js +++ b/packages/netlify-cms-widget-datetime/src/DateTimePreview.js @@ -2,9 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const DatePreview = ({ value }) => ( - {value ? value.toString() : null} -); +function DatePreview({ value }) { + return {value ? value.toString() : null}; +} DatePreview.propTypes = { value: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), diff --git a/packages/netlify-cms-widget-datetime/src/index.js b/packages/netlify-cms-widget-datetime/src/index.js index 612efd06..5103d913 100644 --- a/packages/netlify-cms-widget-datetime/src/index.js +++ b/packages/netlify-cms-widget-datetime/src/index.js @@ -2,13 +2,15 @@ import controlComponent from './DateTimeControl'; import previewComponent from './DateTimePreview'; import schema from './schema'; -const Widget = (opts = {}) => ({ - name: 'datetime', - controlComponent, - previewComponent, - schema, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'datetime', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetDatetime = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetDatetime; diff --git a/packages/netlify-cms-widget-file/src/FilePreview.js b/packages/netlify-cms-widget-file/src/FilePreview.js index 5bfe285f..fbf2e492 100644 --- a/packages/netlify-cms-widget-file/src/FilePreview.js +++ b/packages/netlify-cms-widget-file/src/FilePreview.js @@ -30,9 +30,13 @@ function FileContent(props) { return ; } -const FilePreview = props => ( - {props.value ? : null} -); +function FilePreview(props) { + return ( + + {props.value ? : null} + + ); +} FilePreview.propTypes = { getAsset: PropTypes.func.isRequired, diff --git a/packages/netlify-cms-widget-file/src/index.js b/packages/netlify-cms-widget-file/src/index.js index 7bbad786..56bb45f8 100644 --- a/packages/netlify-cms-widget-file/src/index.js +++ b/packages/netlify-cms-widget-file/src/index.js @@ -3,13 +3,16 @@ import previewComponent from './FilePreview'; import schema from './schema'; const controlComponent = withFileControl(); -const Widget = (opts = {}) => ({ - name: 'file', - controlComponent, - previewComponent, - schema, - ...opts, -}); + +function Widget(opts = {}) { + return { + name: 'file', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetFile = { Widget, controlComponent, previewComponent, withFileControl }; export default NetlifyCmsWidgetFile; diff --git a/packages/netlify-cms-widget-file/src/withFileControl.js b/packages/netlify-cms-widget-file/src/withFileControl.js index 1d9b2aa9..a6e8cab7 100644 --- a/packages/netlify-cms-widget-file/src/withFileControl.js +++ b/packages/netlify-cms-widget-file/src/withFileControl.js @@ -34,7 +34,9 @@ const StyledImage = styled.img` object-fit: contain; `; -const Image = props => ; +function Image(props) { + return ; +} const SortableImage = SortableElement(({ itemValue, getAsset, field }) => { return ( diff --git a/packages/netlify-cms-widget-image/src/ImagePreview.js b/packages/netlify-cms-widget-image/src/ImagePreview.js index c3230456..5bef284c 100644 --- a/packages/netlify-cms-widget-image/src/ImagePreview.js +++ b/packages/netlify-cms-widget-image/src/ImagePreview.js @@ -10,11 +10,11 @@ const StyledImage = styled(({ src }) => { +function StyledImageAsset({ getAsset, value, field }) { return ; -}; +} -const ImagePreviewContent = props => { +function ImagePreviewContent(props) { const { value, getAsset, field } = props; if (Array.isArray(value) || List.isList(value)) { return value.map(val => ( @@ -22,15 +22,15 @@ const ImagePreviewContent = props => { )); } return ; -}; +} -const ImagePreview = props => { +function ImagePreview(props) { return ( {props.value ? : null} ); -}; +} ImagePreview.propTypes = { getAsset: PropTypes.func.isRequired, diff --git a/packages/netlify-cms-widget-image/src/index.js b/packages/netlify-cms-widget-image/src/index.js index df17b78d..48822017 100644 --- a/packages/netlify-cms-widget-image/src/index.js +++ b/packages/netlify-cms-widget-image/src/index.js @@ -3,13 +3,16 @@ import previewComponent from './ImagePreview'; import schema from './schema'; const controlComponent = NetlifyCmsWidgetFile.withFileControl({ forImage: true }); -const Widget = (opts = {}) => ({ - name: 'image', - controlComponent, - previewComponent, - schema, - ...opts, -}); + +function Widget(opts = {}) { + return { + name: 'image', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetImage = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetImage; diff --git a/packages/netlify-cms-widget-list/src/ListControl.js b/packages/netlify-cms-widget-list/src/ListControl.js index 5dca1212..1972ef1b 100644 --- a/packages/netlify-cms-widget-list/src/ListControl.js +++ b/packages/netlify-cms-widget-list/src/ListControl.js @@ -72,13 +72,13 @@ const valueTypes = { MIXED: 'MIXED', }; -const handleSummary = (summary, entry, label, item) => { +function handleSummary(summary, entry, label, item) { const data = stringTemplate.addFileTemplateFields( entry.get('path'), item.set('fields.label', label), ); return stringTemplate.compileStringTemplate(summary, null, '', data); -}; +} export default class ListControl extends React.Component { validations = []; diff --git a/packages/netlify-cms-widget-list/src/__tests__/ListControl.spec.js b/packages/netlify-cms-widget-list/src/__tests__/ListControl.spec.js index acd54baa..aed14b58 100644 --- a/packages/netlify-cms-widget-list/src/__tests__/ListControl.spec.js +++ b/packages/netlify-cms-widget-list/src/__tests__/ListControl.spec.js @@ -18,12 +18,16 @@ jest.mock('netlify-cms-widget-object', () => { }); jest.mock('netlify-cms-ui-default', () => { const actual = jest.requireActual('netlify-cms-ui-default'); - const ListItemTopBar = props => ( - - - {props.children} - - ); + + function ListItemTopBar(props) { + return ( + + + {props.children} + + ); + } + return { ...actual, ListItemTopBar, diff --git a/packages/netlify-cms-widget-list/src/index.js b/packages/netlify-cms-widget-list/src/index.js index f489f0e1..dd8b03f6 100644 --- a/packages/netlify-cms-widget-list/src/index.js +++ b/packages/netlify-cms-widget-list/src/index.js @@ -3,13 +3,16 @@ import NetlifyCmsWidgetObject from 'netlify-cms-widget-object'; import schema from './schema'; const previewComponent = NetlifyCmsWidgetObject.previewComponent; -const Widget = (opts = {}) => ({ - name: 'list', - controlComponent, - previewComponent, - schema, - ...opts, -}); + +function Widget(opts = {}) { + return { + name: 'list', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetList = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetList; diff --git a/packages/netlify-cms-widget-map/src/MapPreview.js b/packages/netlify-cms-widget-map/src/MapPreview.js index 4e208a72..31483c88 100644 --- a/packages/netlify-cms-widget-map/src/MapPreview.js +++ b/packages/netlify-cms-widget-map/src/MapPreview.js @@ -2,9 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const MapPreview = ({ value }) => ( - {value ? value.toString() : null} -); +function MapPreview({ value }) { + return {value ? value.toString() : null}; +} MapPreview.propTypes = { value: PropTypes.string, diff --git a/packages/netlify-cms-widget-map/src/index.js b/packages/netlify-cms-widget-map/src/index.js index 05053711..8b9e4a44 100644 --- a/packages/netlify-cms-widget-map/src/index.js +++ b/packages/netlify-cms-widget-map/src/index.js @@ -3,13 +3,16 @@ import previewComponent from './MapPreview'; import schema from './schema'; const controlComponent = withMapControl(); -const Widget = (opts = {}) => ({ - name: 'map', - controlComponent, - previewComponent, - schema, - ...opts, -}); + +function Widget(opts = {}) { + return { + name: 'map', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetMap = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetMap; diff --git a/packages/netlify-cms-widget-map/src/withMapControl.js b/packages/netlify-cms-widget-map/src/withMapControl.js index a46df5ef..d21e01c8 100644 --- a/packages/netlify-cms-widget-map/src/withMapControl.js +++ b/packages/netlify-cms-widget-map/src/withMapControl.js @@ -15,14 +15,18 @@ const formatOptions = { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857', }; -const getDefaultFormat = () => new GeoJSON(formatOptions); -const getDefaultMap = (target, featuresLayer) => - new Map({ +function getDefaultFormat() { + return new GeoJSON(formatOptions); +} + +function getDefaultMap(target, featuresLayer) { + return new Map({ target, layers: [new TileLayer({ source: new OSMSource() }), featuresLayer], view: new View({ center: [0, 0], zoom: 2 }), }); +} export default function withMapControl({ getFormat, getMap } = {}) { return class MapControl extends React.Component { diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/RawEditor.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/RawEditor.js index 6075c2a6..34c020e4 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/RawEditor.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/RawEditor.js @@ -13,7 +13,8 @@ import { markdownToHtml } from '../serializers'; import { editorStyleVars, EditorControlBar } from '../styles'; import Toolbar from './Toolbar'; -const rawEditorStyles = ({ minimal }) => ` +function rawEditorStyles({ minimal }) { + return ` position: relative; overflow: hidden; overflow-x: auto; @@ -24,6 +25,7 @@ const rawEditorStyles = ({ minimal }) => ` border-top: 0; margin-top: -${editorStyleVars.stickyDistanceBottom}; `; +} const RawEditorContainer = styled.div` position: relative; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/Toolbar.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/Toolbar.js index b45c7414..c21ff167 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/Toolbar.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/Toolbar.js @@ -113,7 +113,11 @@ export default class Toolbar extends React.Component { } = this.props; const isVisible = this.isVisible; const showEditorComponents = !editorComponents || editorComponents.size >= 1; - const showPlugin = ({ id }) => (editorComponents ? editorComponents.includes(id) : true); + + function showPlugin({ id }) { + return editorComponents ? editorComponents.includes(id) : true; + } + const pluginsList = plugins ? plugins.toList().filter(showPlugin) : List(); const headingOptions = { diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/ToolbarButton.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/ToolbarButton.js index 8e8ac5f5..6234f927 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/ToolbarButton.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/ToolbarButton.js @@ -23,16 +23,18 @@ const StyledToolbarButton = styled.button` } `; -const ToolbarButton = ({ type, label, icon, onClick, isActive, disabled }) => ( - onClick && onClick(e, type)} - title={label} - disabled={disabled} - > - {icon ? : label} - -); +function ToolbarButton({ type, label, icon, onClick, isActive, disabled }) { + return ( + onClick && onClick(e, type)} + title={label} + disabled={disabled} + > + {icon ? : label} + + ); +} ToolbarButton.propTypes = { type: PropTypes.string, diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/VisualEditor.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/VisualEditor.js index a163b1a2..7a8e7e6d 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/VisualEditor.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/VisualEditor.js @@ -15,7 +15,8 @@ import { renderBlock, renderInline, renderMark } from './renderers'; import plugins from './plugins/visual'; import schema from './schema'; -const visualEditorStyles = ({ minimal }) => ` +function visualEditorStyles({ minimal }) { + return ` position: relative; overflow: hidden; overflow-x: auto; @@ -30,26 +31,27 @@ const visualEditorStyles = ({ minimal }) => ` flex-direction: column; z-index: ${zIndex.zIndex100}; `; +} const InsertionPoint = styled.div` flex: 1 1 auto; cursor: text; `; -const createEmptyRawDoc = () => { +function createEmptyRawDoc() { const emptyText = Text.create(''); const emptyBlock = Block.create({ object: 'block', type: 'paragraph', nodes: [emptyText] }); return { nodes: [emptyBlock] }; -}; +} -const createSlateValue = (rawValue, { voidCodeBlock }) => { +function createSlateValue(rawValue, { voidCodeBlock }) { const rawDoc = rawValue && markdownToSlate(rawValue, { voidCodeBlock }); const rawDocHasNodes = !isEmpty(get(rawDoc, 'nodes')); const document = Document.fromJSON(rawDocHasNodes ? rawDoc : createEmptyRawDoc()); return Value.create({ document }); -}; +} -export const mergeMediaConfig = (editorComponents, field) => { +export function mergeMediaConfig(editorComponents, field) { // merge editor media library config to image components if (editorComponents.has('image')) { const imageComponent = editorComponents.get('image'); @@ -79,7 +81,7 @@ export const mergeMediaConfig = (editorComponents, field) => { ); } } -}; +} export default class Editor extends React.Component { constructor(props) { diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/__tests__/slate.spec.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/__tests__/slate.spec.js index 01057d79..62d7b870 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/__tests__/slate.spec.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/__tests__/slate.spec.js @@ -38,12 +38,14 @@ describe.skip('slate', () => { ); - const fn = editor => { + + function fn(editor) { editor .deleteBackward() .insertText('b') .setBlocks('heading-one'); - }; + } + const [actual, expected] = run(input, output, fn); expect(actual).toEqual(expected); }); diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/components/Shortcode.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/components/Shortcode.js index fa684990..47c00f50 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/components/Shortcode.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/components/Shortcode.js @@ -24,12 +24,14 @@ export default class Shortcode extends React.Component { const EditorControl = getEditorControl(); const value = dataKey === false ? node.data : fromJS(node.data.get(dataKey)); - const handleChange = (fieldName, value, metadata) => { + function handleChange(fieldName, value, metadata) { const dataValue = dataKey === false ? value : node.data.set('shortcodeData', value); editor.setNodeByKey(node.key, { data: dataValue || Map(), metadata }); - }; + } - const handleFocus = () => editor.moveToRangeOfNode(node); + function handleFocus() { + return editor.moveToRangeOfNode(node); + } return ( !field.isEmpty() && ( diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/components/VoidBlock.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/components/VoidBlock.js index b16010f5..de3f5bf1 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/components/VoidBlock.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/components/VoidBlock.js @@ -3,23 +3,25 @@ import React from 'react'; import { css } from '@emotion/core'; import { zIndex } from 'netlify-cms-ui-default'; -const InsertionPoint = props => ( -
-); +function InsertionPoint(props) { + return ( +
+ ); +} -const VoidBlock = ({ editor, attributes, node, children }) => { - const handleClick = event => { +function VoidBlock({ editor, attributes, node, children }) { + function handleClick(event) { event.stopPropagation(); - }; + } return (
@@ -32,6 +34,6 @@ const VoidBlock = ({ editor, attributes, node, children }) => { )}
); -}; +} export default VoidBlock; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/index.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/index.js index be0cbba0..87d58a22 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/index.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/index.js @@ -10,10 +10,16 @@ const MODE_STORAGE_KEY = 'cms.md-mode'; // TODO: passing the editorControl and components like this is horrible, should // be handled through Redux and a separate registry store for instances let editorControl; +// eslint-disable-next-line func-style let _getEditorComponents = () => []; -export const getEditorControl = () => editorControl; -export const getEditorComponents = () => _getEditorComponents(); +export function getEditorControl() { + return editorControl; +} + +export function getEditorComponents() { + return _getEditorComponents(); +} export default class MarkdownControl extends React.Component { static propTypes = { diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/BreakToDefaultBlock.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/BreakToDefaultBlock.js index e7602370..30a86900 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/BreakToDefaultBlock.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/BreakToDefaultBlock.js @@ -1,21 +1,23 @@ import isHotkey from 'is-hotkey'; -const BreakToDefaultBlock = ({ defaultType }) => ({ - onKeyDown(event, editor, next) { - const { selection, startBlock } = editor.value; - const isEnter = isHotkey('enter', event); - if (!isEnter) { +function BreakToDefaultBlock({ defaultType }) { + return { + onKeyDown(event, editor, next) { + const { selection, startBlock } = editor.value; + const isEnter = isHotkey('enter', event); + if (!isEnter) { + return next(); + } + if (selection.isExpanded) { + editor.delete(); + return next(); + } + if (selection.start.isAtEndOfNode(startBlock) && startBlock.type !== defaultType) { + return editor.insertBlock(defaultType); + } return next(); - } - if (selection.isExpanded) { - editor.delete(); - return next(); - } - if (selection.start.isAtEndOfNode(startBlock) && startBlock.type !== defaultType) { - return editor.insertBlock(defaultType); - } - return next(); - }, -}); + }, + }; +} export default BreakToDefaultBlock; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CloseBlock.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CloseBlock.js index 94260211..9f44685a 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CloseBlock.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CloseBlock.js @@ -1,23 +1,25 @@ import isHotkey from 'is-hotkey'; -const CloseBlock = ({ defaultType }) => ({ - onKeyDown(event, editor, next) { - const { selection, startBlock } = editor.value; - const isBackspace = isHotkey('backspace', event); - if (!isBackspace) { +function CloseBlock({ defaultType }) { + return { + onKeyDown(event, editor, next) { + const { selection, startBlock } = editor.value; + const isBackspace = isHotkey('backspace', event); + if (!isBackspace) { + return next(); + } + if (selection.isExpanded) { + return editor.delete(); + } + if (!selection.start.isAtStartOfNode(startBlock) || startBlock.text.length > 0) { + return next(); + } + if (startBlock.type !== defaultType) { + return editor.setBlocks(defaultType); + } return next(); - } - if (selection.isExpanded) { - return editor.delete(); - } - if (!selection.start.isAtStartOfNode(startBlock) || startBlock.text.length > 0) { - return next(); - } - if (startBlock.type !== defaultType) { - return editor.setBlocks(defaultType); - } - return next(); - }, -}); + }, + }; +} export default CloseBlock; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CommandsAndQueries.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CommandsAndQueries.js index b5d39a39..e5be5261 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CommandsAndQueries.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CommandsAndQueries.js @@ -1,121 +1,123 @@ import { isArray, tail, castArray } from 'lodash'; -const CommandsAndQueries = ({ defaultType }) => ({ - queries: { - atStartOf(editor, node) { - const { selection } = editor.value; - return selection.isCollapsed && selection.start.isAtStartOfNode(node); - }, - getAncestor(editor, firstKey, lastKey) { - if (firstKey === lastKey) { - return editor.value.document.getParent(firstKey); - } - return editor.value.document.getCommonAncestor(firstKey, lastKey); - }, - getOffset(editor, node) { - const parent = editor.value.document.getParent(node.key); - return parent.nodes.indexOf(node); - }, - getSelectedChildren(editor, node) { - return node.nodes.filter(child => editor.isSelected(child)); - }, - getCommonAncestor(editor) { - const { startBlock, endBlock, document: doc } = editor.value; - return doc.getCommonAncestor(startBlock.key, endBlock.key); - }, - getClosestType(editor, node, type) { - const types = castArray(type); - return editor.value.document.getClosest(node.key, n => types.includes(n.type)); - }, - getBlockContainer(editor, node) { - const targetTypes = ['bulleted-list', 'numbered-list', 'list-item', 'quote', 'table-cell']; - const { startBlock, selection } = editor.value; - const target = node - ? editor.value.document.getParent(node.key) - : (selection.isCollapsed && startBlock) || editor.getCommonAncestor(); - if (!target) { - return editor.value.document; - } - if (targetTypes.includes(target.type)) { - return target; - } - return editor.getBlockContainer(target); - }, - isSelected(editor, nodes) { - return castArray(nodes).every(node => { - return editor.value.document.isInRange(node.key, editor.value.selection); - }); - }, - isFirstChild(editor, node) { - return editor.value.document.getParent(node.key).nodes.first().key === node.key; - }, - areSiblings(editor, nodes) { - if (!isArray(nodes) || nodes.length < 2) { - return true; - } - const parent = editor.value.document.getParent(nodes[0].key); - return tail(nodes).every(node => { - return editor.value.document.getParent(node.key).key === parent.key; - }); - }, - everyBlock(editor, type) { - return editor.value.blocks.every(block => block.type === type); - }, - hasMark(editor, type) { - return editor.value.activeMarks.some(mark => mark.type === type); - }, - hasBlock(editor, type) { - return editor.value.blocks.some(node => node.type === type); - }, - hasInline(editor, type) { - return editor.value.inlines.some(node => node.type === type); - }, - }, - commands: { - toggleBlock(editor, type) { - switch (type) { - case 'heading-one': - case 'heading-two': - case 'heading-three': - case 'heading-four': - case 'heading-five': - case 'heading-six': - return editor.setBlocks(editor.everyBlock(type) ? defaultType : type); - case 'quote': - return editor.toggleQuoteBlock(); - case 'numbered-list': - case 'bulleted-list': { - return editor.toggleList(type); +function CommandsAndQueries({ defaultType }) { + return { + queries: { + atStartOf(editor, node) { + const { selection } = editor.value; + return selection.isCollapsed && selection.start.isAtStartOfNode(node); + }, + getAncestor(editor, firstKey, lastKey) { + if (firstKey === lastKey) { + return editor.value.document.getParent(firstKey); } - } - }, - unwrapBlockChildren(editor, block) { - if (!block || block.object !== 'block') { - throw Error(`Expected block but received ${block}.`); - } - const index = editor.value.document.getPath(block.key).last(); - const parent = editor.value.document.getParent(block.key); - editor.withoutNormalizing(() => { - block.nodes.forEach((node, idx) => { - editor.moveNodeByKey(node.key, parent.key, index + idx); + return editor.value.document.getCommonAncestor(firstKey, lastKey); + }, + getOffset(editor, node) { + const parent = editor.value.document.getParent(node.key); + return parent.nodes.indexOf(node); + }, + getSelectedChildren(editor, node) { + return node.nodes.filter(child => editor.isSelected(child)); + }, + getCommonAncestor(editor) { + const { startBlock, endBlock, document: doc } = editor.value; + return doc.getCommonAncestor(startBlock.key, endBlock.key); + }, + getClosestType(editor, node, type) { + const types = castArray(type); + return editor.value.document.getClosest(node.key, n => types.includes(n.type)); + }, + getBlockContainer(editor, node) { + const targetTypes = ['bulleted-list', 'numbered-list', 'list-item', 'quote', 'table-cell']; + const { startBlock, selection } = editor.value; + const target = node + ? editor.value.document.getParent(node.key) + : (selection.isCollapsed && startBlock) || editor.getCommonAncestor(); + if (!target) { + return editor.value.document; + } + if (targetTypes.includes(target.type)) { + return target; + } + return editor.getBlockContainer(target); + }, + isSelected(editor, nodes) { + return castArray(nodes).every(node => { + return editor.value.document.isInRange(node.key, editor.value.selection); }); - editor.removeNodeByKey(block.key); - }); - }, - unwrapNodeToDepth(editor, node, depth) { - let currentDepth = 0; - editor.withoutNormalizing(() => { - while (currentDepth < depth) { - editor.unwrapNodeByKey(node.key); - currentDepth += 1; + }, + isFirstChild(editor, node) { + return editor.value.document.getParent(node.key).nodes.first().key === node.key; + }, + areSiblings(editor, nodes) { + if (!isArray(nodes) || nodes.length < 2) { + return true; } - }); + const parent = editor.value.document.getParent(nodes[0].key); + return tail(nodes).every(node => { + return editor.value.document.getParent(node.key).key === parent.key; + }); + }, + everyBlock(editor, type) { + return editor.value.blocks.every(block => block.type === type); + }, + hasMark(editor, type) { + return editor.value.activeMarks.some(mark => mark.type === type); + }, + hasBlock(editor, type) { + return editor.value.blocks.some(node => node.type === type); + }, + hasInline(editor, type) { + return editor.value.inlines.some(node => node.type === type); + }, }, - unwrapNodeFromAncestor(editor, node, ancestor) { - const depth = ancestor.getDepth(node.key); - editor.unwrapNodeToDepth(node, depth); + commands: { + toggleBlock(editor, type) { + switch (type) { + case 'heading-one': + case 'heading-two': + case 'heading-three': + case 'heading-four': + case 'heading-five': + case 'heading-six': + return editor.setBlocks(editor.everyBlock(type) ? defaultType : type); + case 'quote': + return editor.toggleQuoteBlock(); + case 'numbered-list': + case 'bulleted-list': { + return editor.toggleList(type); + } + } + }, + unwrapBlockChildren(editor, block) { + if (!block || block.object !== 'block') { + throw Error(`Expected block but received ${block}.`); + } + const index = editor.value.document.getPath(block.key).last(); + const parent = editor.value.document.getParent(block.key); + editor.withoutNormalizing(() => { + block.nodes.forEach((node, idx) => { + editor.moveNodeByKey(node.key, parent.key, index + idx); + }); + editor.removeNodeByKey(block.key); + }); + }, + unwrapNodeToDepth(editor, node, depth) { + let currentDepth = 0; + editor.withoutNormalizing(() => { + while (currentDepth < depth) { + editor.unwrapNodeByKey(node.key); + currentDepth += 1; + } + }); + }, + unwrapNodeFromAncestor(editor, node, ancestor) { + const depth = ancestor.getDepth(node.key); + editor.unwrapNodeToDepth(node, depth); + }, }, - }, -}); + }; +} export default CommandsAndQueries; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CopyPasteVisual.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CopyPasteVisual.js index 054d014e..afc3eb00 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CopyPasteVisual.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/CopyPasteVisual.js @@ -4,15 +4,15 @@ import base64 from 'slate-base64-serializer'; import isHotkey from 'is-hotkey'; import { slateToMarkdown, markdownToSlate, htmlToSlate, markdownToHtml } from '../../serializers'; -const CopyPasteVisual = ({ getAsset, resolveWidget }) => { - const handleCopy = (event, editor) => { +function CopyPasteVisual({ getAsset, resolveWidget }) { + function handleCopy(event, editor) { const markdown = slateToMarkdown(editor.value.fragment.toJS()); const html = markdownToHtml(markdown, { getAsset, resolveWidget }); setEventTransfer(event, 'text', markdown); setEventTransfer(event, 'html', html); setEventTransfer(event, 'fragment', base64.serializeNode(editor.value.fragment)); event.preventDefault(); - }; + } return { onPaste(event, editor, next) { @@ -39,6 +39,6 @@ const CopyPasteVisual = ({ getAsset, resolveWidget }) => { editor.delete(); }, }; -}; +} export default CopyPasteVisual; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/ForceInsert.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/ForceInsert.js index f0a5087a..8ff39036 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/ForceInsert.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/ForceInsert.js @@ -1,42 +1,44 @@ -const ForceInsert = ({ defaultType }) => ({ - queries: { - canInsertBeforeNode(editor, node) { - if (!editor.isVoid(node)) { - return true; - } - return !!editor.value.document.getPreviousSibling(node.key); +function ForceInsert({ defaultType }) { + return { + queries: { + canInsertBeforeNode(editor, node) { + if (!editor.isVoid(node)) { + return true; + } + return !!editor.value.document.getPreviousSibling(node.key); + }, + canInsertAfterNode(editor, node) { + if (!editor.isVoid(node)) { + return true; + } + const nextSibling = editor.value.document.getNextSibling(node.key); + return nextSibling && !editor.isVoid(nextSibling); + }, }, - canInsertAfterNode(editor, node) { - if (!editor.isVoid(node)) { - return true; - } - const nextSibling = editor.value.document.getNextSibling(node.key); - return nextSibling && !editor.isVoid(nextSibling); + commands: { + forceInsertBeforeNode(editor, node) { + const block = { type: defaultType, object: 'block' }; + const parent = editor.value.document.getParent(node.key); + return editor + .insertNodeByKey(parent.key, 0, block) + .moveToStartOfNode(parent) + .focus(); + }, + forceInsertAfterNode(editor, node) { + return editor + .moveToEndOfNode(node) + .insertBlock(defaultType) + .focus(); + }, + moveToEndOfDocument(editor) { + const lastBlock = editor.value.document.nodes.last(); + if (editor.isVoid(lastBlock)) { + editor.insertBlock(defaultType); + } + return editor.moveToEndOfNode(lastBlock).focus(); + }, }, - }, - commands: { - forceInsertBeforeNode(editor, node) { - const block = { type: defaultType, object: 'block' }; - const parent = editor.value.document.getParent(node.key); - return editor - .insertNodeByKey(parent.key, 0, block) - .moveToStartOfNode(parent) - .focus(); - }, - forceInsertAfterNode(editor, node) { - return editor - .moveToEndOfNode(node) - .insertBlock(defaultType) - .focus(); - }, - moveToEndOfDocument(editor) { - const lastBlock = editor.value.document.nodes.last(); - if (editor.isVoid(lastBlock)) { - editor.insertBlock(defaultType); - } - return editor.moveToEndOfNode(lastBlock).focus(); - }, - }, -}); + }; +} export default ForceInsert; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Hotkey.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Hotkey.js index 830a72a8..7ed4d49f 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Hotkey.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Hotkey.js @@ -14,7 +14,7 @@ export const HOT_KEY_MAP = { link: 'mod+k', }; -const Hotkey = (key, fn) => { +function Hotkey(key, fn) { return { onKeyDown(event, editor, next) { if (!isHotkey(key, event)) { @@ -24,6 +24,6 @@ const Hotkey = (key, fn) => { editor.command(fn); }, }; -}; +} export default Hotkey; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/LineBreak.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/LineBreak.js index a5475245..3088a24f 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/LineBreak.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/LineBreak.js @@ -1,16 +1,18 @@ import isHotkey from 'is-hotkey'; -const LineBreak = () => ({ - onKeyDown(event, editor, next) { - const isShiftEnter = isHotkey('shift+enter', event); - if (!isShiftEnter) { - return next(); - } - return editor - .insertInline('break') - .insertText('') - .moveToStartOfNextText(); - }, -}); +function LineBreak() { + return { + onKeyDown(event, editor, next) { + const isShiftEnter = isHotkey('shift+enter', event); + if (!isShiftEnter) { + return next(); + } + return editor + .insertInline('break') + .insertText('') + .moveToStartOfNextText(); + }, + }; +} export default LineBreak; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Link.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Link.js index 97e86a5f..83406979 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Link.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Link.js @@ -1,27 +1,29 @@ -const Link = ({ type }) => ({ - commands: { - toggleLink(editor, getUrl) { - if (editor.hasInline(type)) { - editor.unwrapInline(type); - } else { - const url = getUrl(); - if (!url) return; - - const selection = editor.value.selection; - const isCollapsed = selection && selection.isCollapsed; - if (isCollapsed) { - // If no text is selected, use the entered URL as text. - return editor.insertInline({ - type, - data: { url }, - nodes: [{ object: 'text', text: url }], - }); +function Link({ type }) { + return { + commands: { + toggleLink(editor, getUrl) { + if (editor.hasInline(type)) { + editor.unwrapInline(type); } else { - return editor.wrapInline({ type, data: { url } }).moveToEnd(); + const url = getUrl(); + if (!url) return; + + const selection = editor.value.selection; + const isCollapsed = selection && selection.isCollapsed; + if (isCollapsed) { + // If no text is selected, use the entered URL as text. + return editor.insertInline({ + type, + data: { url }, + nodes: [{ object: 'text', text: url }], + }); + } else { + return editor.wrapInline({ type, data: { url } }).moveToEnd(); + } } - } + }, }, - }, -}); + }; +} export default Link; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/List.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/List.js index 80817f4e..76a33b5f 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/List.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/List.js @@ -4,7 +4,7 @@ import { Range, Block } from 'slate'; import isHotkey from 'is-hotkey'; import { assertType } from './util'; -const ListPlugin = ({ defaultType, unorderedListType, orderedListType }) => { +function ListPlugin({ defaultType, unorderedListType, orderedListType }) { const LIST_TYPES = [orderedListType, unorderedListType]; function oppositeListType(type) { @@ -297,6 +297,6 @@ const ListPlugin = ({ defaultType, unorderedListType, orderedListType }) => { return next(); }, }; -}; +} export default ListPlugin; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/QuoteBlock.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/QuoteBlock.js index 85949301..a5a959e1 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/QuoteBlock.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/QuoteBlock.js @@ -4,98 +4,100 @@ import isHotkey from 'is-hotkey'; /** * TODO: highlight a couple list items and hit the quote button. doesn't work. */ -const QuoteBlock = ({ type }) => ({ - commands: { - /** - * Quotes can contain other blocks, even other quotes. If a selection contains quotes, they - * shouldn't be impacted. The selection's immediate parent should be checked - if it's a - * quote, unwrap the quote (as within are only blocks), and if it's not, wrap all selected - * blocks into a quote. Make sure text is wrapped into paragraphs. - */ - toggleQuoteBlock(editor) { - const blockContainer = editor.getBlockContainer(); - if (['bulleted-list', 'numbered-list'].includes(blockContainer.type)) { - const { nodes } = blockContainer; - const allItemsSelected = editor.isSelected([nodes.first(), nodes.last()]); - if (allItemsSelected) { - const nextContainer = editor.getBlockContainer(blockContainer); - if (nextContainer?.type === type) { - editor.unwrapNodeFromAncestor(blockContainer, nextContainer); +function QuoteBlock({ type }) { + return { + commands: { + /** + * Quotes can contain other blocks, even other quotes. If a selection contains quotes, they + * shouldn't be impacted. The selection's immediate parent should be checked - if it's a + * quote, unwrap the quote (as within are only blocks), and if it's not, wrap all selected + * blocks into a quote. Make sure text is wrapped into paragraphs. + */ + toggleQuoteBlock(editor) { + const blockContainer = editor.getBlockContainer(); + if (['bulleted-list', 'numbered-list'].includes(blockContainer.type)) { + const { nodes } = blockContainer; + const allItemsSelected = editor.isSelected([nodes.first(), nodes.last()]); + if (allItemsSelected) { + const nextContainer = editor.getBlockContainer(blockContainer); + if (nextContainer?.type === type) { + editor.unwrapNodeFromAncestor(blockContainer, nextContainer); + } else { + editor.wrapBlockByKey(blockContainer.key, type); + } } else { - editor.wrapBlockByKey(blockContainer.key, type); + const blockContainerParent = editor.value.document.getParent(blockContainer.key); + editor.withoutNormalizing(() => { + const selectedListItems = nodes.filter(node => editor.isSelected(node)); + const newList = Block.create(blockContainer.type); + editor.unwrapNodeByKey(selectedListItems.first()); + const offset = editor.getOffset(selectedListItems.first()); + editor.insertNodeByKey(blockContainerParent.key, offset + 1, newList); + selectedListItems.forEach(({ key }, idx) => + editor.moveNodeByKey(key, newList.key, idx), + ); + editor.wrapBlockByKey(newList.key, type); + }); } - } else { - const blockContainerParent = editor.value.document.getParent(blockContainer.key); - editor.withoutNormalizing(() => { - const selectedListItems = nodes.filter(node => editor.isSelected(node)); - const newList = Block.create(blockContainer.type); - editor.unwrapNodeByKey(selectedListItems.first()); - const offset = editor.getOffset(selectedListItems.first()); - editor.insertNodeByKey(blockContainerParent.key, offset + 1, newList); - selectedListItems.forEach(({ key }, idx) => - editor.moveNodeByKey(key, newList.key, idx), - ); - editor.wrapBlockByKey(newList.key, type); - }); + return; } - return; - } - const blocks = editor.value.blocks; - const firstBlockKey = blocks.first().key; - const lastBlockKey = blocks.last().key; - const ancestor = editor.getAncestor(firstBlockKey, lastBlockKey); - if (ancestor.type === type) { - editor.unwrapBlockChildren(ancestor); - } else { - editor.wrapBlock(type); - } + const blocks = editor.value.blocks; + const firstBlockKey = blocks.first().key; + const lastBlockKey = blocks.last().key; + const ancestor = editor.getAncestor(firstBlockKey, lastBlockKey); + if (ancestor.type === type) { + editor.unwrapBlockChildren(ancestor); + } else { + editor.wrapBlock(type); + } + }, }, - }, - onKeyDown(event, editor, next) { - if (!isHotkey('enter', event) && !isHotkey('backspace', event)) { - return next(); - } - const { selection, startBlock, document: doc } = editor.value; - const parent = doc.getParent(startBlock.key); - const isQuote = parent.type === type; - if (!isQuote) { - return next(); - } - if (isHotkey('enter', event)) { - if (selection.isExpanded) { - editor.delete(); - } - - // If the quote is empty, remove it. - if (editor.atStartOf(parent)) { - return editor.unwrapBlockByKey(parent.key); - } - - if (editor.atStartOf(startBlock)) { - const offset = editor.getOffset(startBlock); - return editor - .splitNodeByKey(parent.key, offset) - .unwrapBlockByKey(editor.value.document.getParent(startBlock.key).key); - } - - return next(); - } else if (isHotkey('backspace', event)) { - if (selection.isExpanded) { - editor.delete(); - } - if (!editor.atStartOf(parent)) { + onKeyDown(event, editor, next) { + if (!isHotkey('enter', event) && !isHotkey('backspace', event)) { return next(); } - const previousParentSibling = doc.getPreviousSibling(parent.key); - if (previousParentSibling && previousParentSibling.type === type) { - return editor.mergeNodeByKey(parent.key); + const { selection, startBlock, document: doc } = editor.value; + const parent = doc.getParent(startBlock.key); + const isQuote = parent.type === type; + if (!isQuote) { + return next(); } + if (isHotkey('enter', event)) { + if (selection.isExpanded) { + editor.delete(); + } - return editor.unwrapNodeByKey(startBlock.key); - } - return next(); - }, -}); + // If the quote is empty, remove it. + if (editor.atStartOf(parent)) { + return editor.unwrapBlockByKey(parent.key); + } + + if (editor.atStartOf(startBlock)) { + const offset = editor.getOffset(startBlock); + return editor + .splitNodeByKey(parent.key, offset) + .unwrapBlockByKey(editor.value.document.getParent(startBlock.key).key); + } + + return next(); + } else if (isHotkey('backspace', event)) { + if (selection.isExpanded) { + editor.delete(); + } + if (!editor.atStartOf(parent)) { + return next(); + } + const previousParentSibling = doc.getPreviousSibling(parent.key); + if (previousParentSibling && previousParentSibling.type === type) { + return editor.mergeNodeByKey(parent.key); + } + + return editor.unwrapNodeByKey(startBlock.key); + } + return next(); + }, + }; +} export default QuoteBlock; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/SelectAll.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/SelectAll.js index 914d5261..e9762bed 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/SelectAll.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/SelectAll.js @@ -1,14 +1,16 @@ import isHotkey from 'is-hotkey'; -const SelectAll = () => ({ - onKeyDown(event, editor, next) { - const isModA = isHotkey('mod+a', event); - if (!isModA) { - return next(); - } - event.preventDefault(); - return editor.moveToRangeOfDocument(); - }, -}); +function SelectAll() { + return { + onKeyDown(event, editor, next) { + const isModA = isHotkey('mod+a', event); + if (!isModA) { + return next(); + } + event.preventDefault(); + return editor.moveToRangeOfDocument(); + }, + }; +} export default SelectAll; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Shortcode.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Shortcode.js index fc42c436..a0b9251b 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Shortcode.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/Shortcode.js @@ -1,6 +1,6 @@ import { Text, Block } from 'slate'; -const createShortcodeBlock = shortcodeConfig => { +function createShortcodeBlock(shortcodeConfig) { // Handle code block component if (shortcodeConfig.type === 'code-block') { return Block.create({ type: shortcodeConfig.type, data: { shortcodeNew: true } }); @@ -25,23 +25,25 @@ const createShortcodeBlock = shortcodeConfig => { }, nodes, }); -}; +} -const Shortcode = ({ defaultType }) => ({ - commands: { - insertShortcode(editor, shortcodeConfig) { - const block = createShortcodeBlock(shortcodeConfig); - const { focusBlock } = editor.value; +function Shortcode({ defaultType }) { + return { + commands: { + insertShortcode(editor, shortcodeConfig) { + const block = createShortcodeBlock(shortcodeConfig); + const { focusBlock } = editor.value; - if (focusBlock.text === '' && focusBlock.type === defaultType) { - editor.replaceNodeByKey(focusBlock.key, block); - } else { - editor.insertBlock(block); - } + if (focusBlock.text === '' && focusBlock.type === defaultType) { + editor.replaceNodeByKey(focusBlock.key, block); + } else { + editor.insertBlock(block); + } - editor.focus(); + editor.focus(); + }, }, - }, -}); + }; +} export default Shortcode; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/visual.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/visual.js index 85a1ec2e..28f6ece7 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/visual.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/plugins/visual.js @@ -14,39 +14,45 @@ import Shortcode from './Shortcode'; import { SLATE_DEFAULT_BLOCK_TYPE as defaultType } from '../../types'; import Hotkey, { HOT_KEY_MAP } from './Hotkey'; -const plugins = ({ getAsset, resolveWidget, t }) => [ - { - onKeyDown(event, editor, next) { - if (isHotkey('mod+j', event)) { - console.log(JSON.stringify(editor.value.document.toJS(), null, 2)); - } - next(); +function plugins({ getAsset, resolveWidget, t }) { + return [ + { + onKeyDown(event, editor, next) { + if (isHotkey('mod+j', event)) { + console.log(JSON.stringify(editor.value.document.toJS(), null, 2)); + } + next(); + }, }, - }, - Hotkey(HOT_KEY_MAP['bold'], e => e.toggleMark('bold')), - Hotkey(HOT_KEY_MAP['code'], e => e.toggleMark('code')), - Hotkey(HOT_KEY_MAP['italic'], e => e.toggleMark('italic')), - Hotkey(HOT_KEY_MAP['strikethrough'], e => e.toggleMark('strikethrough')), - Hotkey(HOT_KEY_MAP['heading-one'], e => e.toggleBlock('heading-one')), - Hotkey(HOT_KEY_MAP['heading-two'], e => e.toggleBlock('heading-two')), - Hotkey(HOT_KEY_MAP['heading-three'], e => e.toggleBlock('heading-three')), - Hotkey(HOT_KEY_MAP['heading-four'], e => e.toggleBlock('heading-four')), - Hotkey(HOT_KEY_MAP['heading-five'], e => e.toggleBlock('heading-five')), - Hotkey(HOT_KEY_MAP['heading-six'], e => e.toggleBlock('heading-six')), - Hotkey(HOT_KEY_MAP['link'], e => - e.toggleLink(() => window.prompt(t('editor.editorWidgets.markdown.linkPrompt'))), - ), - CommandsAndQueries({ defaultType }), - QuoteBlock({ defaultType, type: 'quote' }), - ListPlugin({ defaultType, unorderedListType: 'bulleted-list', orderedListType: 'numbered-list' }), - Link({ type: 'link' }), - LineBreak(), - BreakToDefaultBlock({ defaultType }), - CloseBlock({ defaultType }), - SelectAll(), - ForceInsert({ defaultType }), - CopyPasteVisual({ getAsset, resolveWidget }), - Shortcode({ defaultType }), -]; + Hotkey(HOT_KEY_MAP['bold'], e => e.toggleMark('bold')), + Hotkey(HOT_KEY_MAP['code'], e => e.toggleMark('code')), + Hotkey(HOT_KEY_MAP['italic'], e => e.toggleMark('italic')), + Hotkey(HOT_KEY_MAP['strikethrough'], e => e.toggleMark('strikethrough')), + Hotkey(HOT_KEY_MAP['heading-one'], e => e.toggleBlock('heading-one')), + Hotkey(HOT_KEY_MAP['heading-two'], e => e.toggleBlock('heading-two')), + Hotkey(HOT_KEY_MAP['heading-three'], e => e.toggleBlock('heading-three')), + Hotkey(HOT_KEY_MAP['heading-four'], e => e.toggleBlock('heading-four')), + Hotkey(HOT_KEY_MAP['heading-five'], e => e.toggleBlock('heading-five')), + Hotkey(HOT_KEY_MAP['heading-six'], e => e.toggleBlock('heading-six')), + Hotkey(HOT_KEY_MAP['link'], e => + e.toggleLink(() => window.prompt(t('editor.editorWidgets.markdown.linkPrompt'))), + ), + CommandsAndQueries({ defaultType }), + QuoteBlock({ defaultType, type: 'quote' }), + ListPlugin({ + defaultType, + unorderedListType: 'bulleted-list', + orderedListType: 'numbered-list', + }), + Link({ type: 'link' }), + LineBreak(), + BreakToDefaultBlock({ defaultType }), + CloseBlock({ defaultType }), + SelectAll(), + ForceInsert({ defaultType }), + CopyPasteVisual({ getAsset, resolveWidget }), + Shortcode({ defaultType }), + ]; +} export default plugins; diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/renderers.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/renderers.js index 33b9715f..fc180c2f 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/renderers.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/renderers.js @@ -123,56 +123,118 @@ const StyledTd = styled.td` /** * Mark Components */ -const Bold = props => {props.children}; -const Italic = props => {props.children}; -const Strikethrough = props => {props.children}; -const Code = props => {props.children}; +function Bold(props) { + return {props.children}; +} + +function Italic(props) { + return {props.children}; +} + +function Strikethrough(props) { + return {props.children}; +} + +function Code(props) { + return {props.children}; +} /** * Node Components */ -const Paragraph = props => {props.children}; -const ListItem = props => {props.children}; -const Quote = props => {props.children}; -const CodeBlock = props => ( - - {props.children} - -); -const HeadingOne = props => {props.children}; -const HeadingTwo = props => {props.children}; -const HeadingThree = props => {props.children}; -const HeadingFour = props => {props.children}; -const HeadingFive = props => {props.children}; -const HeadingSix = props => {props.children}; -const Table = props => ( - - {props.children} - -); -const TableRow = props => {props.children}; -const TableCell = props => {props.children}; -const ThematicBreak = props => ( - -); -const Break = props =>
; -const BulletedList = props => {props.children}; -const NumberedList = props => ( - - {props.children} - -); -const Link = props => { +function Paragraph(props) { + return {props.children}; +} + +function ListItem(props) { + return {props.children}; +} + +function Quote(props) { + return {props.children}; +} + +function CodeBlock(props) { + return ( + + {props.children} + + ); +} + +function HeadingOne(props) { + return {props.children}; +} + +function HeadingTwo(props) { + return {props.children}; +} + +function HeadingThree(props) { + return {props.children}; +} + +function HeadingFour(props) { + return {props.children}; +} + +function HeadingFive(props) { + return {props.children}; +} + +function HeadingSix(props) { + return {props.children}; +} + +function Table(props) { + return ( + + {props.children} + + ); +} + +function TableRow(props) { + return {props.children}; +} + +function TableCell(props) { + return {props.children}; +} + +function ThematicBreak(props) { + return ( + + ); +} + +function Break(props) { + return
; +} + +function BulletedList(props) { + return {props.children}; +} + +function NumberedList(props) { + return ( + + {props.children} + + ); +} + +function Link(props) { const data = props.node.get('data'); const url = data.get('url'); const title = data.get('title'); @@ -181,9 +243,9 @@ const Link = props => { {props.children} ); -}; +} -const Image = props => { +function Image(props) { const data = props.node.get('data'); const marks = data.get('marks'); const url = data.get('url'); @@ -196,87 +258,93 @@ const Image = props => { return renderMark({ mark, children: acc }); }, image); return result; -}; +} -export const renderMark = () => props => { - switch (props.mark.type) { - case 'bold': - return ; - case 'italic': - return ; - case 'strikethrough': - return ; - case 'code': - return ; - } -}; +export function renderMark() { + return props => { + switch (props.mark.type) { + case 'bold': + return ; + case 'italic': + return ; + case 'strikethrough': + return ; + case 'code': + return ; + } + }; +} -export const renderInline = () => props => { - switch (props.node.type) { - case 'link': - return ; - case 'image': - return ; - case 'break': - return ; - } -}; +export function renderInline() { + return props => { + switch (props.node.type) { + case 'link': + return ; + case 'image': + return ; + case 'break': + return ; + } + }; +} -export const renderBlock = ({ classNameWrapper, codeBlockComponent }) => props => { - switch (props.node.type) { - case 'paragraph': - return ; - case 'list-item': - return ; - case 'quote': - return ; - case 'code-block': - if (codeBlockComponent) { +export function renderBlock({ classNameWrapper, codeBlockComponent }) { + return props => { + switch (props.node.type) { + case 'paragraph': + return ; + case 'list-item': + return ; + case 'quote': + return ; + case 'code-block': + if (codeBlockComponent) { + return ( + + + + ); + } + return ; + case 'heading-one': + return ; + case 'heading-two': + return ; + case 'heading-three': + return ; + case 'heading-four': + return ; + case 'heading-five': + return ; + case 'heading-six': + return ; + case 'table': + return ; + case 'table-row': + return ; + case 'table-cell': + return ; + case 'thematic-break': return ( - + ); - } - return ; - case 'heading-one': - return ; - case 'heading-two': - return ; - case 'heading-three': - return ; - case 'heading-four': - return ; - case 'heading-five': - return ; - case 'heading-six': - return ; - case 'table': - return
; - case 'table-row': - return ; - case 'table-cell': - return ; - case 'thematic-break': - return ( - - - - ); - case 'bulleted-list': - return ; - case 'numbered-list': - return ; - case 'shortcode': - return ( - - - - ); - } -}; + case 'bulleted-list': + return ; + case 'numbered-list': + return ; + case 'shortcode': + return ( + + + + ); + } + }; +} diff --git a/packages/netlify-cms-widget-markdown/src/MarkdownControl/schema.js b/packages/netlify-cms-widget-markdown/src/MarkdownControl/schema.js index 2af9870b..ab01f865 100644 --- a/packages/netlify-cms-widget-markdown/src/MarkdownControl/schema.js +++ b/packages/netlify-cms-widget-markdown/src/MarkdownControl/schema.js @@ -26,247 +26,249 @@ const codeBlockOverride = { isVoid: true, }; -const schema = ({ voidCodeBlock } = {}) => ({ - rules: [ - /** - * Document - */ - { - match: [{ object: 'document' }], - nodes: [ - { - match: [ - { type: 'paragraph' }, - { type: 'heading-one' }, - { type: 'heading-two' }, - { type: 'heading-three' }, - { type: 'heading-four' }, - { type: 'heading-five' }, - { type: 'heading-six' }, - { type: 'quote' }, - { type: 'code-block' }, - { type: 'bulleted-list' }, - { type: 'numbered-list' }, - { type: 'thematic-break' }, - { type: 'table' }, - { type: 'shortcode' }, - ], - min: 1, - }, - ], - normalize: (editor, error) => { - switch (error.code) { - // If no blocks present, insert one. - case 'child_min_invalid': { - const node = { object: 'block', type: 'paragraph' }; - editor.insertNodeByKey(error.node.key, 0, node); - return; - } - } - }, - }, - - /** - * Block Containers - */ - { - match: [ - { object: 'block', type: 'quote' }, - { object: 'block', type: 'list-item' }, - ], - nodes: [ - { - match: [ - { type: 'paragraph' }, - { type: 'heading-one' }, - { type: 'heading-two' }, - { type: 'heading-three' }, - { type: 'heading-four' }, - { type: 'heading-five' }, - { type: 'heading-six' }, - { type: 'quote' }, - { type: 'code-block' }, - { type: 'bulleted-list' }, - { type: 'numbered-list' }, - { type: 'thematic-break' }, - { type: 'table' }, - { type: 'shortcode' }, - ], - }, - ], - }, - - /** - * List Items - */ - { - match: [{ object: 'block', type: 'list-item' }], - parent: [{ type: 'bulleted-list' }, { type: 'numbered-list' }], - }, - - /** - * Blocks - */ - { - match: [ - { object: 'block', type: 'paragraph' }, - { object: 'block', type: 'heading-one' }, - { object: 'block', type: 'heading-two' }, - { object: 'block', type: 'heading-three' }, - { object: 'block', type: 'heading-four' }, - { object: 'block', type: 'heading-five' }, - { object: 'block', type: 'heading-six' }, - { object: 'block', type: 'table-cell' }, - { object: 'inline', type: 'link' }, - ], - nodes: [ - { - match: [{ object: 'text' }, { type: 'link' }, { type: 'image' }, { type: 'break' }], - }, - ], - }, - - /** - * Bulleted List - */ - { - match: [{ object: 'block', type: 'bulleted-list' }], - nodes: [ - { - match: [{ type: 'list-item' }], - min: 1, - }, - ], - next: [ - { type: 'paragraph' }, - { type: 'heading-one' }, - { type: 'heading-two' }, - { type: 'heading-three' }, - { type: 'heading-four' }, - { type: 'heading-five' }, - { type: 'heading-six' }, - { type: 'quote' }, - { type: 'code-block' }, - { type: 'numbered-list' }, - { type: 'thematic-break' }, - { type: 'table' }, - { type: 'shortcode' }, - ], - normalize: (editor, error) => { - switch (error.code) { - // If a list has no list items, remove the list - case 'child_min_invalid': - editor.removeNodeByKey(error.node.key); - return; - - // If two bulleted lists are immediately adjacent, join them - case 'next_sibling_type_invalid': - if (error.next.type === 'bulleted-list') { - editor.mergeNodeByKey(error.next.key); +function schema({ voidCodeBlock } = {}) { + return { + rules: [ + /** + * Document + */ + { + match: [{ object: 'document' }], + nodes: [ + { + match: [ + { type: 'paragraph' }, + { type: 'heading-one' }, + { type: 'heading-two' }, + { type: 'heading-three' }, + { type: 'heading-four' }, + { type: 'heading-five' }, + { type: 'heading-six' }, + { type: 'quote' }, + { type: 'code-block' }, + { type: 'bulleted-list' }, + { type: 'numbered-list' }, + { type: 'thematic-break' }, + { type: 'table' }, + { type: 'shortcode' }, + ], + min: 1, + }, + ], + normalize: (editor, error) => { + switch (error.code) { + // If no blocks present, insert one. + case 'child_min_invalid': { + const node = { object: 'block', type: 'paragraph' }; + editor.insertNodeByKey(error.node.key, 0, node); + return; } - return; - } - }, - }, - - /** - * Numbered List - */ - { - match: [{ object: 'block', type: 'numbered-list' }], - nodes: [ - { - match: [{ type: 'list-item' }], - min: 1, - }, - ], - next: [ - { type: 'paragraph' }, - { type: 'heading-one' }, - { type: 'heading-two' }, - { type: 'heading-three' }, - { type: 'heading-four' }, - { type: 'heading-five' }, - { type: 'heading-six' }, - { type: 'quote' }, - { type: 'code-block' }, - { type: 'bulleted-list' }, - { type: 'thematic-break' }, - { type: 'table' }, - { type: 'shortcode' }, - ], - normalize: (editor, error) => { - switch (error.code) { - // If a list has no list items, remove the list - case 'child_min_invalid': - editor.removeNodeByKey(error.node.key); - return; - - // If two numbered lists are immediately adjacent, join them - case 'next_sibling_type_invalid': { - if (error.next.type === 'numbered-list') { - editor.mergeNodeByKey(error.next.key); - } - return; } - } + }, }, - }, - /** - * Voids - */ - { - match: [ - { object: 'inline', type: 'image' }, - { object: 'inline', type: 'break' }, - { object: 'block', type: 'thematic-break' }, - { object: 'block', type: 'shortcode' }, - ], - isVoid: true, - }, + /** + * Block Containers + */ + { + match: [ + { object: 'block', type: 'quote' }, + { object: 'block', type: 'list-item' }, + ], + nodes: [ + { + match: [ + { type: 'paragraph' }, + { type: 'heading-one' }, + { type: 'heading-two' }, + { type: 'heading-three' }, + { type: 'heading-four' }, + { type: 'heading-five' }, + { type: 'heading-six' }, + { type: 'quote' }, + { type: 'code-block' }, + { type: 'bulleted-list' }, + { type: 'numbered-list' }, + { type: 'thematic-break' }, + { type: 'table' }, + { type: 'shortcode' }, + ], + }, + ], + }, - /** - * Table - */ - { - match: [{ object: 'block', type: 'table' }], - nodes: [ - { - match: [{ object: 'block', type: 'table-row' }], + /** + * List Items + */ + { + match: [{ object: 'block', type: 'list-item' }], + parent: [{ type: 'bulleted-list' }, { type: 'numbered-list' }], + }, + + /** + * Blocks + */ + { + match: [ + { object: 'block', type: 'paragraph' }, + { object: 'block', type: 'heading-one' }, + { object: 'block', type: 'heading-two' }, + { object: 'block', type: 'heading-three' }, + { object: 'block', type: 'heading-four' }, + { object: 'block', type: 'heading-five' }, + { object: 'block', type: 'heading-six' }, + { object: 'block', type: 'table-cell' }, + { object: 'inline', type: 'link' }, + ], + nodes: [ + { + match: [{ object: 'text' }, { type: 'link' }, { type: 'image' }, { type: 'break' }], + }, + ], + }, + + /** + * Bulleted List + */ + { + match: [{ object: 'block', type: 'bulleted-list' }], + nodes: [ + { + match: [{ type: 'list-item' }], + min: 1, + }, + ], + next: [ + { type: 'paragraph' }, + { type: 'heading-one' }, + { type: 'heading-two' }, + { type: 'heading-three' }, + { type: 'heading-four' }, + { type: 'heading-five' }, + { type: 'heading-six' }, + { type: 'quote' }, + { type: 'code-block' }, + { type: 'numbered-list' }, + { type: 'thematic-break' }, + { type: 'table' }, + { type: 'shortcode' }, + ], + normalize: (editor, error) => { + switch (error.code) { + // If a list has no list items, remove the list + case 'child_min_invalid': + editor.removeNodeByKey(error.node.key); + return; + + // If two bulleted lists are immediately adjacent, join them + case 'next_sibling_type_invalid': + if (error.next.type === 'bulleted-list') { + editor.mergeNodeByKey(error.next.key); + } + return; + } }, - ], - }, + }, - /** - * Table Row - */ - { - match: [{ object: 'block', type: 'table-row' }], - nodes: [ - { - match: [{ object: 'block', type: 'table-cell' }], + /** + * Numbered List + */ + { + match: [{ object: 'block', type: 'numbered-list' }], + nodes: [ + { + match: [{ type: 'list-item' }], + min: 1, + }, + ], + next: [ + { type: 'paragraph' }, + { type: 'heading-one' }, + { type: 'heading-two' }, + { type: 'heading-three' }, + { type: 'heading-four' }, + { type: 'heading-five' }, + { type: 'heading-six' }, + { type: 'quote' }, + { type: 'code-block' }, + { type: 'bulleted-list' }, + { type: 'thematic-break' }, + { type: 'table' }, + { type: 'shortcode' }, + ], + normalize: (editor, error) => { + switch (error.code) { + // If a list has no list items, remove the list + case 'child_min_invalid': + editor.removeNodeByKey(error.node.key); + return; + + // If two numbered lists are immediately adjacent, join them + case 'next_sibling_type_invalid': { + if (error.next.type === 'numbered-list') { + editor.mergeNodeByKey(error.next.key); + } + return; + } + } }, - ], - }, + }, - /** - * Marks - */ - { - match: [ - { object: 'mark', type: 'bold' }, - { object: 'mark', type: 'italic' }, - { object: 'mark', type: 'strikethrough' }, - { object: 'mark', type: 'code' }, - ], - }, + /** + * Voids + */ + { + match: [ + { object: 'inline', type: 'image' }, + { object: 'inline', type: 'break' }, + { object: 'block', type: 'thematic-break' }, + { object: 'block', type: 'shortcode' }, + ], + isVoid: true, + }, - /** - * Overrides - */ - voidCodeBlock ? codeBlockOverride : codeBlock, - ], -}); + /** + * Table + */ + { + match: [{ object: 'block', type: 'table' }], + nodes: [ + { + match: [{ object: 'block', type: 'table-row' }], + }, + ], + }, + + /** + * Table Row + */ + { + match: [{ object: 'block', type: 'table-row' }], + nodes: [ + { + match: [{ object: 'block', type: 'table-cell' }], + }, + ], + }, + + /** + * Marks + */ + { + match: [ + { object: 'mark', type: 'bold' }, + { object: 'mark', type: 'italic' }, + { object: 'mark', type: 'strikethrough' }, + { object: 'mark', type: 'code' }, + ], + }, + + /** + * Overrides + */ + voidCodeBlock ? codeBlockOverride : codeBlock, + ], + }; +} export default schema; diff --git a/packages/netlify-cms-widget-markdown/src/index.js b/packages/netlify-cms-widget-markdown/src/index.js index 69539361..30827206 100644 --- a/packages/netlify-cms-widget-markdown/src/index.js +++ b/packages/netlify-cms-widget-markdown/src/index.js @@ -2,13 +2,15 @@ import controlComponent from './MarkdownControl'; import previewComponent from './MarkdownPreview'; import schema from './schema'; -const Widget = (opts = {}) => ({ - name: 'markdown', - controlComponent, - previewComponent, - schema, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'markdown', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetMarkdown = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetMarkdown; diff --git a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/commonmark.spec.js b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/commonmark.spec.js index bf971ce5..a74eaf36 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/commonmark.spec.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/commonmark.spec.js @@ -68,10 +68,12 @@ const onlys = [ */ const reader = new commonmark.Parser(); const writer = new commonmark.HtmlRenderer(); -const parseWithCommonmark = markdown => { + +function parseWithCommonmark(markdown) { const parsed = reader.parse(markdown); return writer.render(parsed); -}; +} + const parse = flow([markdownToSlate, slateToMarkdown]); /** diff --git a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkAllowHtmlEntities.spec.js b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkAllowHtmlEntities.spec.js index 18c6722f..0def91ae 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkAllowHtmlEntities.spec.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkAllowHtmlEntities.spec.js @@ -2,7 +2,7 @@ import unified from 'unified'; import markdownToRemark from 'remark-parse'; import remarkAllowHtmlEntities from '../remarkAllowHtmlEntities'; -const process = markdown => { +function process(markdown) { const mdast = unified() .use(markdownToRemark) .use(remarkAllowHtmlEntities) @@ -18,7 +18,7 @@ const process = markdown => { * ]} */ return mdast.children[0].children[0].value; -}; +} describe('remarkAllowHtmlEntities', () => { it('should not decode HTML entities', () => { diff --git a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkEscapeMarkdownEntities.spec.js b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkEscapeMarkdownEntities.spec.js index a8336d14..cf9426b8 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkEscapeMarkdownEntities.spec.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkEscapeMarkdownEntities.spec.js @@ -2,14 +2,14 @@ import unified from 'unified'; import u from 'unist-builder'; import remarkEscapeMarkdownEntities from '../remarkEscapeMarkdownEntities'; -const process = text => { +function process(text) { const tree = u('root', [u('text', text)]); const escapedMdast = unified() .use(remarkEscapeMarkdownEntities) .runSync(tree); return escapedMdast.children[0].value; -}; +} describe('remarkEscapeMarkdownEntities', () => { it('should escape common markdown entities', () => { diff --git a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkPaddedLinks.spec.js b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkPaddedLinks.spec.js index 1ec68d16..a4165c80 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkPaddedLinks.spec.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkPaddedLinks.spec.js @@ -3,18 +3,20 @@ import markdownToRemark from 'remark-parse'; import remarkToMarkdown from 'remark-stringify'; import remarkPaddedLinks from '../remarkPaddedLinks'; -const input = markdown => - unified() +function input(markdown) { + return unified() .use(markdownToRemark) .use(remarkPaddedLinks) .use(remarkToMarkdown) .processSync(markdown).contents; +} -const output = markdown => - unified() +function output(markdown) { + return unified() .use(markdownToRemark) .use(remarkToMarkdown) .processSync(markdown).contents; +} describe('remarkPaddedLinks', () => { it('should move leading and trailing spaces outside of a link', () => { diff --git a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkShortcodes.spec.js b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkShortcodes.spec.js index 410982fb..d5dede15 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkShortcodes.spec.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkShortcodes.spec.js @@ -2,7 +2,10 @@ import { remarkParseShortcodes } from '../remarkShortcodes'; // Stub of Remark Parser function process(value, plugins, processEat = () => {}) { - const eat = () => processEat; + function eat() { + return processEat; + } + function Parser() {} Parser.prototype.blockTokenizers = {}; Parser.prototype.blockMethods = []; diff --git a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkStripTrailingBreaks.spec.js b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkStripTrailingBreaks.spec.js index a7b0500f..56654597 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkStripTrailingBreaks.spec.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/__tests__/remarkStripTrailingBreaks.spec.js @@ -2,14 +2,14 @@ import unified from 'unified'; import u from 'unist-builder'; import remarkStripTrailingBreaks from '../remarkStripTrailingBreaks'; -const process = children => { +function process(children) { const tree = u('root', children); const strippedMdast = unified() .use(remarkStripTrailingBreaks) .runSync(tree); return strippedMdast.children; -}; +} describe('remarkStripTrailingBreaks', () => { it('should remove trailing breaks at the end of a block', () => { diff --git a/packages/netlify-cms-widget-markdown/src/serializers/index.js b/packages/netlify-cms-widget-markdown/src/serializers/index.js index de4711b8..812c1079 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/index.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/index.js @@ -58,7 +58,7 @@ import { getEditorComponents } from '../MarkdownControl'; /** * Deserialize a Markdown string to an MDAST. */ -export const markdownToRemark = markdown => { +export function markdownToRemark(markdown) { /** * Parse the Markdown string input to an MDAST. */ @@ -77,7 +77,7 @@ export const markdownToRemark = markdown => { .runSync(parsed); return result; -}; +} /** * Remove named tokenizers from the parser, effectively deactivating them. @@ -92,7 +92,7 @@ function markdownToRemarkRemoveTokenizers({ inlineTokenizers }) { /** * Serialize an MDAST to a Markdown string. */ -export const remarkToMarkdown = obj => { +export function remarkToMarkdown(obj) { /** * Rewrite the remark-stringify text visitor to simply return the text value, * without encoding or escaping any characters. This means we're completely @@ -143,12 +143,12 @@ export const remarkToMarkdown = obj => { * Return markdown with trailing whitespace removed. */ return trimEnd(markdown); -}; +} /** * Convert Markdown to HTML. */ -export const markdownToHtml = (markdown, { getAsset, resolveWidget } = {}) => { +export function markdownToHtml(markdown, { getAsset, resolveWidget } = {}) { const mdast = markdownToRemark(markdown); const hast = unified() @@ -166,13 +166,13 @@ export const markdownToHtml = (markdown, { getAsset, resolveWidget } = {}) => { .stringify(hast); return html; -}; +} /** * Deserialize an HTML string to Slate's Raw AST. Currently used for HTML * pastes. */ -export const htmlToSlate = html => { +export function htmlToSlate(html) { const hast = unified() .use(htmlToRehype, { fragment: true }) .parse(html); @@ -190,12 +190,12 @@ export const htmlToSlate = html => { .runSync(mdast); return slateRaw; -}; +} /** * Convert Markdown to Slate's Raw AST. */ -export const markdownToSlate = (markdown, { voidCodeBlock } = {}) => { +export function markdownToSlate(markdown, { voidCodeBlock } = {}) { const mdast = markdownToRemark(markdown); const slateRaw = unified() @@ -204,7 +204,7 @@ export const markdownToSlate = (markdown, { voidCodeBlock } = {}) => { .runSync(mdast); return slateRaw; -}; +} /** * Convert a Slate Raw AST to Markdown. @@ -215,8 +215,8 @@ export const markdownToSlate = (markdown, { voidCodeBlock } = {}) => { * MDAST. The conversion is manual because Unified can only operate on Unist * trees. */ -export const slateToMarkdown = (raw, { voidCodeBlock } = {}) => { +export function slateToMarkdown(raw, { voidCodeBlock } = {}) { const mdast = slateToRemark(raw, { voidCodeBlock }); const markdown = remarkToMarkdown(mdast); return markdown; -}; +} diff --git a/packages/netlify-cms-widget-markdown/src/serializers/rehypePaperEmoji.js b/packages/netlify-cms-widget-markdown/src/serializers/rehypePaperEmoji.js index 873c6b79..cda7bab9 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/rehypePaperEmoji.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/rehypePaperEmoji.js @@ -4,12 +4,13 @@ * replaces the images with the emoji characters. */ export default function rehypePaperEmoji() { - const transform = node => { + function transform(node) { if (node.tagName === 'img' && node.properties.dataEmojiCh) { return { type: 'text', value: node.properties.dataEmojiCh }; } node.children = node.children ? node.children.map(transform) : node.children; return node; - }; + } + return transform; } diff --git a/packages/netlify-cms-widget-markdown/src/serializers/remarkEscapeMarkdownEntities.js b/packages/netlify-cms-widget-markdown/src/serializers/remarkEscapeMarkdownEntities.js index 8c696a48..52956ce4 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/remarkEscapeMarkdownEntities.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/remarkEscapeMarkdownEntities.js @@ -236,7 +236,7 @@ function escape(delim) { * stringification. */ export default function remarkEscapeMarkdownEntities() { - const transform = (node, index) => { + function transform(node, index) { /** * Shortcode nodes will intentionally inject markdown entities in text node * children not be escaped. @@ -262,7 +262,7 @@ export default function remarkEscapeMarkdownEntities() { * Always return nodes with recursively mapped children. */ return { ...node, ...children }; - }; + } return transform; } diff --git a/packages/netlify-cms-widget-markdown/src/serializers/remarkSlate.js b/packages/netlify-cms-widget-markdown/src/serializers/remarkSlate.js index f11ae0a3..455e11d5 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/remarkSlate.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/remarkSlate.js @@ -28,11 +28,19 @@ const markMap = { inlineCode: 'code', }; -const isInline = node => node.object === 'inline'; -const isText = node => node.object === 'text'; -const isMarksEqual = (node1, node2) => isEqual(node1.marks, node2.marks); +function isInline(node) { + return node.object === 'inline'; +} -export const wrapInlinesWithTexts = children => { +function isText(node) { + return node.object === 'text'; +} + +function isMarksEqual(node1, node2) { + return isEqual(node1.marks, node2.marks); +} + +export function wrapInlinesWithTexts(children) { if (children.length <= 0) { return children; } @@ -63,9 +71,9 @@ export const wrapInlinesWithTexts = children => { } return children; -}; +} -export const mergeAdjacentTexts = children => { +export function mergeAdjacentTexts(children) { if (children.length <= 0) { return children; } @@ -96,7 +104,7 @@ export const mergeAdjacentTexts = children => { } return mergedChildren; -}; +} /** * A Remark plugin for converting an MDAST to Slate Raw AST. Remark plugins diff --git a/packages/netlify-cms-widget-markdown/src/serializers/remarkStripTrailingBreaks.js b/packages/netlify-cms-widget-markdown/src/serializers/remarkStripTrailingBreaks.js index 50e1bf0e..36933fac 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/remarkStripTrailingBreaks.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/remarkStripTrailingBreaks.js @@ -10,7 +10,7 @@ import mdastToString from 'mdast-util-to-string'; * these artifacts in resulting markdown. */ export default function remarkStripTrailingBreaks() { - const transform = node => { + function transform(node) { if (node.children) { node.children = node.children .map((child, idx, children) => { @@ -50,6 +50,7 @@ export default function remarkStripTrailingBreaks() { .map(transform); } return node; - }; + } + return transform; } diff --git a/packages/netlify-cms-widget-markdown/src/serializers/slateRemark.js b/packages/netlify-cms-widget-markdown/src/serializers/slateRemark.js index d0c3f139..3b9a375a 100644 --- a/packages/netlify-cms-widget-markdown/src/serializers/slateRemark.js +++ b/packages/netlify-cms-widget-markdown/src/serializers/slateRemark.js @@ -208,6 +208,10 @@ export default function slateToRemark(raw, { voidCodeBlock }) { return { leadingWhitespace, centerNodes, trailingWhitespace }; } + function createText(text) { + return text && u('html', text); + } + function convertInlineAndTextChildren(nodes = []) { const convertedNodes = []; let remainingNodes = nodes; @@ -243,7 +247,7 @@ export default function slateToRemark(raw, { voidCodeBlock }) { remainingNodes = remainder; continue; } - const createText = text => text && u('html', text); + const normalizedNodes = [ createText(leadingWhitespace), markNode, diff --git a/packages/netlify-cms-widget-number/src/NumberPreview.js b/packages/netlify-cms-widget-number/src/NumberPreview.js index b4bb4466..f1cdd305 100644 --- a/packages/netlify-cms-widget-number/src/NumberPreview.js +++ b/packages/netlify-cms-widget-number/src/NumberPreview.js @@ -2,7 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const NumberPreview = ({ value }) => {value}; +function NumberPreview({ value }) { + return {value}; +} NumberPreview.propTypes = { value: PropTypes.node, diff --git a/packages/netlify-cms-widget-number/src/index.js b/packages/netlify-cms-widget-number/src/index.js index 19c98909..3df5e75e 100644 --- a/packages/netlify-cms-widget-number/src/index.js +++ b/packages/netlify-cms-widget-number/src/index.js @@ -2,13 +2,15 @@ import controlComponent from './NumberControl'; import previewComponent from './NumberPreview'; import schema from './schema'; -const Widget = (opts = {}) => ({ - name: 'number', - controlComponent, - previewComponent, - schema, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'number', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetNumber = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetNumber; diff --git a/packages/netlify-cms-widget-object/src/ObjectPreview.js b/packages/netlify-cms-widget-object/src/ObjectPreview.js index 605c3f55..40847fac 100644 --- a/packages/netlify-cms-widget-object/src/ObjectPreview.js +++ b/packages/netlify-cms-widget-object/src/ObjectPreview.js @@ -2,11 +2,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const ObjectPreview = ({ field }) => ( - - {(field && field.get('fields')) || field.get('field') || null} - -); +function ObjectPreview({ field }) { + return ( + + {(field && field.get('fields')) || field.get('field') || null} + + ); +} ObjectPreview.propTypes = { field: PropTypes.node, diff --git a/packages/netlify-cms-widget-object/src/index.js b/packages/netlify-cms-widget-object/src/index.js index 5fbcbfdf..3cbdb1c7 100644 --- a/packages/netlify-cms-widget-object/src/index.js +++ b/packages/netlify-cms-widget-object/src/index.js @@ -2,13 +2,15 @@ import controlComponent from './ObjectControl'; import previewComponent from './ObjectPreview'; import schema from './schema'; -const Widget = (opts = {}) => ({ - name: 'object', - controlComponent, - previewComponent, - schema, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'object', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetObject = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetObject; diff --git a/packages/netlify-cms-widget-relation/src/RelationControl.js b/packages/netlify-cms-widget-relation/src/RelationControl.js index 63d48c7d..b910ca9f 100644 --- a/packages/netlify-cms-widget-relation/src/RelationControl.js +++ b/packages/netlify-cms-widget-relation/src/RelationControl.js @@ -8,9 +8,11 @@ import { reactSelectStyles } from 'netlify-cms-ui-default'; import { stringTemplate } from 'netlify-cms-lib-widgets'; import { FixedSizeList } from 'react-window'; -const Option = ({ index, style, data }) =>
{data.options[index]}
; +function Option({ index, style, data }) { + return
{data.options[index]}
; +} -const MenuList = props => { +function MenuList(props) { if (props.isLoading || props.options.length <= 0 || !Array.isArray(props.children)) { return props.children; } @@ -28,7 +30,7 @@ const MenuList = props => { {Option} ); -}; +} function optionToString(option) { return option && option.value ? option.value : ''; diff --git a/packages/netlify-cms-widget-relation/src/RelationPreview.js b/packages/netlify-cms-widget-relation/src/RelationPreview.js index 4b763bf8..da998273 100644 --- a/packages/netlify-cms-widget-relation/src/RelationPreview.js +++ b/packages/netlify-cms-widget-relation/src/RelationPreview.js @@ -2,7 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const RelationPreview = ({ value }) => {value}; +function RelationPreview({ value }) { + return {value}; +} RelationPreview.propTypes = { value: PropTypes.node, diff --git a/packages/netlify-cms-widget-relation/src/__tests__/relation.spec.js b/packages/netlify-cms-widget-relation/src/__tests__/relation.spec.js index a21a925f..f60e85ba 100644 --- a/packages/netlify-cms-widget-relation/src/__tests__/relation.spec.js +++ b/packages/netlify-cms-widget-relation/src/__tests__/relation.spec.js @@ -4,7 +4,10 @@ import { render, fireEvent, waitFor } from '@testing-library/react'; import { NetlifyCmsWidgetRelation } from '../'; jest.mock('react-window', () => { - const FixedSizeList = props => props.itemData.options; + function FixedSizeList(props) { + return props.itemData.options; + } + return { FixedSizeList, }; @@ -45,7 +48,7 @@ const nestedFieldConfig = { value_field: 'title', }; -const generateHits = length => { +function generateHits(length) { const hits = Array.from({ length }, (val, idx) => { const title = `Post # ${idx + 1}`; const slug = `post-number-${idx + 1}`; @@ -89,7 +92,7 @@ const generateHits = length => { data: { title: 'JSON post', slug: 'post-json', body: 'Body json' }, }, ]; -}; +} const simpleFileCollectionHits = [{ data: { categories: ['category 1', 'category 2'] } }]; diff --git a/packages/netlify-cms-widget-relation/src/index.js b/packages/netlify-cms-widget-relation/src/index.js index c03df9ff..12f7f946 100644 --- a/packages/netlify-cms-widget-relation/src/index.js +++ b/packages/netlify-cms-widget-relation/src/index.js @@ -2,13 +2,15 @@ import controlComponent from './RelationControl'; import previewComponent from './RelationPreview'; import schema from './schema'; -const Widget = (opts = {}) => ({ - name: 'relation', - controlComponent, - previewComponent, - schema, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'relation', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetRelation = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetRelation; diff --git a/packages/netlify-cms-widget-select/src/SelectPreview.js b/packages/netlify-cms-widget-select/src/SelectPreview.js index 80152613..17ccac63 100644 --- a/packages/netlify-cms-widget-select/src/SelectPreview.js +++ b/packages/netlify-cms-widget-select/src/SelectPreview.js @@ -4,20 +4,24 @@ import { List } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const ListPreview = ({ values }) => ( -
    - {values.map((value, idx) => ( -
  • {value}
  • - ))} -
-); +function ListPreview({ values }) { + return ( +
    + {values.map((value, idx) => ( +
  • {value}
  • + ))} +
+ ); +} -const SelectPreview = ({ value }) => ( - - {value && (List.isList(value) ? : value)} - {!value && null} - -); +function SelectPreview({ value }) { + return ( + + {value && (List.isList(value) ? : value)} + {!value && null} + + ); +} SelectPreview.propTypes = { value: PropTypes.oneOfType([PropTypes.string, ImmutablePropTypes.list]), diff --git a/packages/netlify-cms-widget-select/src/index.js b/packages/netlify-cms-widget-select/src/index.js index 13bd330e..481490aa 100644 --- a/packages/netlify-cms-widget-select/src/index.js +++ b/packages/netlify-cms-widget-select/src/index.js @@ -2,13 +2,15 @@ import controlComponent from './SelectControl'; import previewComponent from './SelectPreview'; import schema from './schema'; -const Widget = (opts = {}) => ({ - name: 'select', - controlComponent, - previewComponent, - schema, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'select', + controlComponent, + previewComponent, + schema, + ...opts, + }; +} export const NetlifyCmsWidgetSelect = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetSelect; diff --git a/packages/netlify-cms-widget-string/src/StringPreview.js b/packages/netlify-cms-widget-string/src/StringPreview.js index 3c82bcad..4e591b05 100644 --- a/packages/netlify-cms-widget-string/src/StringPreview.js +++ b/packages/netlify-cms-widget-string/src/StringPreview.js @@ -2,7 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const StringPreview = ({ value }) => {value}; +function StringPreview({ value }) { + return {value}; +} StringPreview.propTypes = { value: PropTypes.node, diff --git a/packages/netlify-cms-widget-string/src/index.js b/packages/netlify-cms-widget-string/src/index.js index b6202c5b..ddb84c98 100644 --- a/packages/netlify-cms-widget-string/src/index.js +++ b/packages/netlify-cms-widget-string/src/index.js @@ -1,12 +1,14 @@ import controlComponent from './StringControl'; import previewComponent from './StringPreview'; -const Widget = (opts = {}) => ({ - name: 'string', - controlComponent, - previewComponent, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'string', + controlComponent, + previewComponent, + ...opts, + }; +} export const NetlifyCmsWidgetString = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetString; diff --git a/packages/netlify-cms-widget-text/src/TextPreview.js b/packages/netlify-cms-widget-text/src/TextPreview.js index f3417216..ec5fb8f0 100644 --- a/packages/netlify-cms-widget-text/src/TextPreview.js +++ b/packages/netlify-cms-widget-text/src/TextPreview.js @@ -2,7 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; -const TextPreview = ({ value }) => {value}; +function TextPreview({ value }) { + return {value}; +} TextPreview.propTypes = { value: PropTypes.node, diff --git a/packages/netlify-cms-widget-text/src/index.js b/packages/netlify-cms-widget-text/src/index.js index f4475d8c..98def7ca 100644 --- a/packages/netlify-cms-widget-text/src/index.js +++ b/packages/netlify-cms-widget-text/src/index.js @@ -1,12 +1,14 @@ import controlComponent from './TextControl'; import previewComponent from './TextPreview'; -const Widget = (opts = {}) => ({ - name: 'text', - controlComponent, - previewComponent, - ...opts, -}); +function Widget(opts = {}) { + return { + name: 'text', + controlComponent, + previewComponent, + ...opts, + }; +} export const NetlifyCmsWidgetText = { Widget, controlComponent, previewComponent }; export default NetlifyCmsWidgetText; diff --git a/scripts/externals.js b/scripts/externals.js index 21c8faba..6066d336 100644 --- a/scripts/externals.js +++ b/scripts/externals.js @@ -6,8 +6,8 @@ const path = require('path'); * netlify-cms-something to NetlifyCmsSomething * @param {} string */ -const toGlobalName = name => - `${name}` +function toGlobalName(name) { + return `${name}` .replace(new RegExp(/[-_/]+/, 'g'), ' ') .replace(new RegExp(/[^\w\s]/, 'g'), '') .replace( @@ -16,6 +16,7 @@ const toGlobalName = name => ) .replace(new RegExp(/\s/, 'g'), '') .replace(new RegExp(/\w/), s => s.toUpperCase()); +} const packages = fs.readdirSync(path.resolve(__dirname, '../packages')); diff --git a/scripts/webpack.js b/scripts/webpack.js index 97ef00a3..06a03905 100644 --- a/scripts/webpack.js +++ b/scripts/webpack.js @@ -7,42 +7,49 @@ const pkg = require(path.join(process.cwd(), 'package.json')); const isProduction = process.env.NODE_ENV === 'production'; const isTest = process.env.NODE_ENV === 'test'; -const moduleNameToPath = libName => path.resolve(__dirname, '..', 'node_modules', libName); -const rules = () => ({ - js: () => ({ - test: /\.(ts|js)x?$/, - exclude: /node_modules/, - use: { - loader: 'babel-loader', - options: { - rootMode: 'upward', +function moduleNameToPath(libName) { + return path.resolve(__dirname, '..', 'node_modules', libName); +} + +function rules() { + return { + js: () => ({ + test: /\.(ts|js)x?$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + rootMode: 'upward', + }, }, - }, - }), - css: () => [ - { - test: /\.css$/, - include: ['ol', 'redux-notifications', 'react-datetime', 'codemirror'].map(moduleNameToPath), - use: ['to-string-loader', 'css-loader'], - }, - ], - svg: () => ({ - test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, - exclude: [/node_modules/], - use: 'svg-inline-loader', - }), -}); + }), + css: () => [ + { + test: /\.css$/, + include: ['ol', 'redux-notifications', 'react-datetime', 'codemirror'].map( + moduleNameToPath, + ), + use: ['to-string-loader', 'css-loader'], + }, + ], + svg: () => ({ + test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, + exclude: [/node_modules/], + use: 'svg-inline-loader', + }), + }; +} -const plugins = () => { +function plugins() { return { ignoreEsprima: () => new webpack.IgnorePlugin(/^esprima$/, /js-yaml/), ignoreMomentOptionalDeps: () => new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), friendlyErrors: () => new FriendlyErrorsWebpackPlugin(), }; -}; +} -const stats = () => { +function stats() { if (isProduction) { return { builtAt: false, @@ -60,12 +67,13 @@ const stats = () => { return { all: false, }; -}; +} const umdPath = path.resolve(process.cwd(), 'dist'); const umdDirPath = path.resolve(process.cwd(), 'dist/umd'); const cjsPath = path.resolve(process.cwd(), 'dist/cjs'); -const targetOutputs = () => { + +function targetOutputs() { console.log(`Building [${pkg.name}, library: ${toGlobalName(pkg.name)}]`); return { umd: { @@ -93,7 +101,7 @@ const targetOutputs = () => { libraryTarget: 'window', }, }; -}; +} const umdExternals = Object.keys(pkg.peerDependencies || {}).reduce((previous, key) => { if (!externals[key]) throw `Missing external [${key}]`; @@ -106,45 +114,51 @@ const umdExternals = Object.keys(pkg.peerDependencies || {}).reduce((previous, k * getting multiple configs and add the new output in targetOutputs if needed. * Default: umd */ -const baseConfig = ({ target = isProduction ? 'umd' : 'umddir' } = {}) => ({ - context: process.cwd(), - mode: isProduction ? 'production' : 'development', - entry: './src', - output: targetOutputs()[target], - module: { - rules: flatMap(Object.values(rules()), rule => rule()), - }, - resolve: { - extensions: ['.ts', '.tsx', '.js', '.json'], - alias: { - moment$: 'moment/moment.js', +function baseConfig({ target = isProduction ? 'umd' : 'umddir' } = {}) { + return { + context: process.cwd(), + mode: isProduction ? 'production' : 'development', + entry: './src', + output: targetOutputs()[target], + module: { + rules: flatMap(Object.values(rules()), rule => rule()), }, - }, - plugins: Object.values(plugins()).map(plugin => plugin()), - devtool: isTest ? '' : 'source-map', - target: 'web', + resolve: { + extensions: ['.ts', '.tsx', '.js', '.json'], + alias: { + moment$: 'moment/moment.js', + }, + }, + plugins: Object.values(plugins()).map(plugin => plugin()), + devtool: isTest ? '' : 'source-map', + target: 'web', - /** - * Exclude peer dependencies from package bundles. - */ - externals: - target.substr(0, 3) === 'umd' - ? umdExternals - : (context, request, cb) => { - const externals = Object.keys(pkg.peerDependencies || {}); - const isPeerDep = dep => new RegExp(`^${dep}($|/)`).test(request); - return externals.some(isPeerDep) ? cb(null, request) : cb(); - }, - stats: stats(), -}); + /** + * Exclude peer dependencies from package bundles. + */ + externals: + target.substr(0, 3) === 'umd' + ? umdExternals + : (context, request, cb) => { + const externals = Object.keys(pkg.peerDependencies || {}); -const getConfig = ({ baseOnly = false } = {}) => { + function isPeerDep(dep) { + return new RegExp(`^${dep}($|/)`).test(request); + } + + return externals.some(isPeerDep) ? cb(null, request) : cb(); + }, + stats: stats(), + }; +} + +function getConfig({ baseOnly = false } = {}) { if (baseOnly) { // netlify-cms build return baseConfig({ target: 'umd' }); } return [baseConfig({ target: 'umd' })]; -}; +} module.exports = { getConfig, diff --git a/website/gatsby-node.js b/website/gatsby-node.js index 70568bb8..0369cb1a 100644 --- a/website/gatsby-node.js +++ b/website/gatsby-node.js @@ -49,7 +49,9 @@ exports.createPages = async ({ graphql, actions }) => { }); }; -const pad = n => (n >= 10 ? n : `0${n}`); +function pad(n) { + return n >= 10 ? n : `0${n}`; +} exports.onCreateNode = ({ node, actions, getNode }) => { const { createNodeField } = actions; diff --git a/website/src/cms/cms.js b/website/src/cms/cms.js index dd2e9dbb..8048b62b 100644 --- a/website/src/cms/cms.js +++ b/website/src/cms/cms.js @@ -23,11 +23,13 @@ function getEmotionCache() { return emotionCache; } -const PreviewContainer = ({ children, highlight }) => ( - - {highlight ? {children} : children} - -); +function PreviewContainer({ children, highlight }) { + return ( + + {highlight ? {children} : children} + + ); +} class Highlight extends React.Component { constructor(props) { @@ -56,7 +58,7 @@ class Highlight extends React.Component { } } -const BlogPostPreview = ({ entry, widgetFor }) => { +function BlogPostPreview({ entry, widgetFor }) { const data = entry.get('data'); return ( @@ -68,56 +70,64 @@ const BlogPostPreview = ({ entry, widgetFor }) => { /> ); -}; +} -const CommunityPreview = ({ entry }) => { +function CommunityPreview({ entry }) { const { title, headline, subhead, sections } = entry.get('data').toJS(); return ( ); -}; +} -const DocsPreview = ({ entry, widgetFor }) => ( - - - -); +function DocsPreview({ entry, widgetFor }) { + return ( + + + + ); +} -const WidgetDocPreview = ({ entry, widgetFor }) => ( - - - -); +function WidgetDocPreview({ entry, widgetFor }) { + return ( + + + + ); +} -const ReleasePreview = ({ entry }) => ( - - ({ - version: release.get('version'), - date: dayjs(release.get('date')).format('MMMM D, YYYY'), - description: release.get('description'), - })) - .toJS()} - /> - -); +function ReleasePreview({ entry }) { + return ( + + ({ + version: release.get('version'), + date: dayjs(release.get('date')).format('MMMM D, YYYY'), + description: release.get('description'), + })) + .toJS()} + /> + + ); +} -const NotificationPreview = ({ entry }) => ( - - {entry - .getIn(['data', 'notifications']) - .filter(notif => notif.get('published')) - .map((notif, idx) => ( - - {notif.get('message')} - - ))} - -); +function NotificationPreview({ entry }) { + return ( + + {entry + .getIn(['data', 'notifications']) + .filter(notif => notif.get('published')) + .map((notif, idx) => ( + + {notif.get('message')} + + ))} + + ); +} CMS.registerPreviewTemplate('blog', BlogPostPreview); siteConfig.menu.docs.forEach(group => { diff --git a/website/src/components/chat-button.js b/website/src/components/chat-button.js index 9790fb93..fd37c775 100644 --- a/website/src/components/chat-button.js +++ b/website/src/components/chat-button.js @@ -9,10 +9,12 @@ const ChatLink = styled.a` cursor: pointer; `; -const ChatButton = () => ( - - - -); +function ChatButton() { + return ( + + + + ); +} export default ChatButton; diff --git a/website/src/components/community-channels-list.js b/website/src/components/community-channels-list.js index 6183c6d4..00fe5a8a 100644 --- a/website/src/components/community-channels-list.js +++ b/website/src/components/community-channels-list.js @@ -40,17 +40,19 @@ const StyledCommunityChannelsList = styled.ul` } `; -const CommunityChannelsList = ({ channels }) => ( - - {channels.map(({ title, description, url }, idx) => ( -
  • - - {title} -

    {description}

    -
    -
  • - ))} -
    -); +function CommunityChannelsList({ channels }) { + return ( + + {channels.map(({ title, description, url }, idx) => ( +
  • + + {title} +

    {description}

    +
    +
  • + ))} +
    + ); +} export default CommunityChannelsList; diff --git a/website/src/components/community.js b/website/src/components/community.js index 901fcd3c..69b5dfe6 100644 --- a/website/src/components/community.js +++ b/website/src/components/community.js @@ -11,42 +11,44 @@ import Grid from './grid'; import CommunityChannelsList from './community-channels-list'; import theme from '../theme'; -const Community = ({ headline, subhead, sections }) => ( - <> - -
    - - - - - - -
    -
    +function Community({ headline, subhead, sections }) { + return ( + <> + +
    + + + + + + +
    +
    - - - -
    - {sections.map(({ title: sectionTitle, channels }, channelIdx) => ( - - {sectionTitle} - - - ))} -
    -
    -
    -
    - -); + + + +
    + {sections.map(({ title: sectionTitle, channels }, channelIdx) => ( + + {sectionTitle} + + + ))} +
    +
    +
    +
    + + ); +} export default Community; diff --git a/website/src/components/docs-nav.js b/website/src/components/docs-nav.js index 7863d9a5..cf2339f9 100644 --- a/website/src/components/docs-nav.js +++ b/website/src/components/docs-nav.js @@ -62,12 +62,12 @@ const NavLink = styled(Link)` } `; -const DocsNav = ({ items, location }) => { +function DocsNav({ items, location }) { const [isMenuOpen, setMenuOpen] = useState(false); - const toggleMenu = () => { + function toggleMenu() { setMenuOpen(isOpen => !isOpen); - }; + } return ( @@ -94,7 +94,7 @@ const DocsNav = ({ items, location }) => { ); -}; +} export default DocsNav; diff --git a/website/src/components/docsearch.js b/website/src/components/docsearch.js index 82131b6d..92427789 100644 --- a/website/src/components/docsearch.js +++ b/website/src/components/docsearch.js @@ -26,7 +26,7 @@ const SearchField = styled.input` outline: 0; `; -const DocSearch = () => { +function DocSearch() { const [enabled, setEnabled] = useState(true); useEffect(() => { @@ -51,6 +51,6 @@ const DocSearch = () => { ); -}; +} export default memo(DocSearch); diff --git a/website/src/components/edit-link.js b/website/src/components/edit-link.js index a90e84f7..742a3cb5 100644 --- a/website/src/components/edit-link.js +++ b/website/src/components/edit-link.js @@ -1,44 +1,46 @@ import React from 'react'; import { css } from '@emotion/core'; -const EditLink = ({ collection, filename }) => ( - -); + /> + {' '} + Edit this page + + + ); +} export default EditLink; diff --git a/website/src/components/event-box.js b/website/src/components/event-box.js index 5d09aab9..00fae3b7 100644 --- a/website/src/components/event-box.js +++ b/website/src/components/event-box.js @@ -64,7 +64,7 @@ const CalDates = styled.p` const CalCta = styled.div``; -const EventBox = ({ title, cta }) => { +function EventBox({ title, cta }) { const [loading, setLoading] = useState(true); const [eventDate, setEventDate] = useState(''); @@ -121,6 +121,6 @@ const EventBox = ({ title, cta }) => { ); -}; +} export default EventBox; diff --git a/website/src/components/features.js b/website/src/components/features.js index b22a34b9..393228fc 100644 --- a/website/src/components/features.js +++ b/website/src/components/features.js @@ -25,19 +25,22 @@ const Text = styled.p` } `; -const FeatureItem = ({ feature, description, imgpath, kind }) => ( - - {imgpath && } - - <Markdownify source={feature} /> - - - - - -); +function FeatureItem({ feature, description, imgpath, kind }) { + return ( + + {imgpath && } + + <Markdownify source={feature} /> + + + + + + ); +} -const Features = ({ items, kind }) => - items.map(item => ); +function Features({ items, kind }) { + return items.map(item => ); +} export default Features; diff --git a/website/src/components/footer.js b/website/src/components/footer.js index 9e4003a4..bb60e863 100644 --- a/website/src/components/footer.js +++ b/website/src/components/footer.js @@ -60,37 +60,39 @@ const Info = styled.div` } `; -const Footer = ({ buttons }) => ( - - - - - {buttons.map(btn => ( - - {btn.name} - - ))} - - -

    - - Distributed under MIT License - {' '} - ·{' '} - - Code of Conduct - -

    -
    -
    -
    -
    -); +function Footer({ buttons }) { + return ( + + + + + {buttons.map(btn => ( + + {btn.name} + + ))} + + +

    + + Distributed under MIT License + {' '} + ·{' '} + + Code of Conduct + +

    +
    +
    +
    +
    + ); +} export default Footer; diff --git a/website/src/components/header.js b/website/src/components/header.js index 3c988a49..1b16d712 100644 --- a/website/src/components/header.js +++ b/website/src/components/header.js @@ -145,7 +145,7 @@ const NOTIFS_QUERY = graphql` } `; -const Header = ({ hasHeroBelow }) => { +function Header({ hasHeroBelow }) { const [scrolled, setScrolled] = useState(false); const [isNavOpen, setNavOpen] = useState(false); const [isSearchOpen, setSearchOpen] = useState(false); @@ -159,23 +159,23 @@ const Header = ({ hasHeroBelow }) => { }; }, []); - const handleScroll = () => { + function handleScroll() { const currentWindowPos = document.documentElement.scrollTop || document.body.scrollTop; const scrolled = currentWindowPos > 0; setScrolled(scrolled); - }; + } - const handleMenuBtnClick = () => { + function handleMenuBtnClick() { setNavOpen(s => !s); setSearchOpen(false); - }; + } - const handleSearchBtnClick = () => { + function handleSearchBtnClick() { setSearchOpen(s => !s); setNavOpen(false); - }; + } return ( @@ -241,6 +241,6 @@ const Header = ({ hasHeroBelow }) => { }} ); -}; +} export default Header; diff --git a/website/src/components/home-section.js b/website/src/components/home-section.js index 5ca37699..eb97c251 100644 --- a/website/src/components/home-section.js +++ b/website/src/components/home-section.js @@ -21,16 +21,18 @@ const Text = styled.div` margin: 0 auto; `; -const HomeSection = ({ title, text, children, ...props }) => ( - - -
    - {title} - {text && {text}} -
    - {children} -
    -
    -); +function HomeSection({ title, text, children, ...props }) { + return ( + + +
    + {title} + {text && {text}} +
    + {children} +
    +
    + ); +} export default HomeSection; diff --git a/website/src/components/layout.js b/website/src/components/layout.js index 8913d214..312e26ea 100644 --- a/website/src/components/layout.js +++ b/website/src/components/layout.js @@ -28,14 +28,16 @@ const LAYOUT_QUERY = graphql` } `; -export const LayoutTemplate = ({ children }) => ( - - - {children} - -); +export function LayoutTemplate({ children }) { + return ( + + + {children} + + ); +} -const Layout = ({ hasPageHero, children }) => { +function Layout({ hasPageHero, children }) { return ( {data => { @@ -63,6 +65,6 @@ const Layout = ({ hasPageHero, children }) => { }} ); -}; +} export default Layout; diff --git a/website/src/components/markdown.js b/website/src/components/markdown.js index d98459b0..f60ac554 100644 --- a/website/src/components/markdown.js +++ b/website/src/components/markdown.js @@ -125,11 +125,11 @@ const StyledMarkdown = styled.div` } `; -const Markdown = ({ body, html }) => { +function Markdown({ body, html }) { if (body) { return {body}; } return ; -}; +} export default Markdown; diff --git a/website/src/components/markdownify.js b/website/src/components/markdownify.js index c0236831..f58d36b4 100644 --- a/website/src/components/markdownify.js +++ b/website/src/components/markdownify.js @@ -1,8 +1,8 @@ import React, { Fragment } from 'react'; import Markdown from 'react-markdown'; -const Markdownify = ({ source }) => ( - {source} -); +function Markdownify({ source }) { + return {source}; +} export default Markdownify; diff --git a/website/src/components/notification.js b/website/src/components/notification.js index 70fe4d4f..48fe8971 100644 --- a/website/src/components/notification.js +++ b/website/src/components/notification.js @@ -38,10 +38,12 @@ const Notif = styled.a` } `; -const Notification = ({ url, loud, children }) => ( - - {children} - -); +function Notification({ url, loud, children }) { + return ( + + {children} + + ); +} export default Notification; diff --git a/website/src/components/notifications.js b/website/src/components/notifications.js index e5ddb321..825e30f8 100644 --- a/website/src/components/notifications.js +++ b/website/src/components/notifications.js @@ -1,12 +1,12 @@ import React from 'react'; import Notification from './notification'; -const Notifications = ({ notifications }) => { +function Notifications({ notifications }) { return notifications.map((node, i) => ( {node.message} )); -}; +} export default Notifications; diff --git a/website/src/components/page-hero.js b/website/src/components/page-hero.js index 4f6fa140..cbb0c597 100644 --- a/website/src/components/page-hero.js +++ b/website/src/components/page-hero.js @@ -6,24 +6,26 @@ import Container from './container'; import theme from '../theme'; import { mq } from '../utils'; -const PageHero = ({ children }) => ( -
    - {children} -
    -); + padding-bottom: ${theme.space[6]}; + + ${mq[3]} { + padding-top: ${theme.space[6]}; + padding-bottom: ${theme.space[8]}; + } + `} + > + {children} + + ); +} export default PageHero; diff --git a/website/src/components/release.js b/website/src/components/release.js index cf0ad2d0..39fd971f 100644 --- a/website/src/components/release.js +++ b/website/src/components/release.js @@ -27,7 +27,7 @@ const Version = styled.span` color: ${theme.colors.gray}; `; -const Release = ({ version, versionPrevious, date, description, url }) => { +function Release({ version, versionPrevious, date, description, url }) { const displayDate = moment(date).format('MMMM D, YYYY'); const defaultUrl = `https://github.com/netlify/netlify-cms/compare/netlify-cms@${versionPrevious}...netlify-cms@${version}`; @@ -63,6 +63,6 @@ const Release = ({ version, versionPrevious, date, description, url }) => { ); -}; +} export default Release; diff --git a/website/src/components/sidebar-layout.js b/website/src/components/sidebar-layout.js index 416f42bf..29f3465e 100644 --- a/website/src/components/sidebar-layout.js +++ b/website/src/components/sidebar-layout.js @@ -10,19 +10,21 @@ const Children = styled.div` padding-left: 2rem; `; -const SidebarLayout = ({ sidebar, children }) => ( - - {sidebar &&
    {sidebar}
    } - {children} -
    -); +function SidebarLayout({ sidebar, children }) { + return ( + + {sidebar &&
    {sidebar}
    } + {children} +
    + ); +} export default SidebarLayout; diff --git a/website/src/components/table-of-contents.js b/website/src/components/table-of-contents.js index a58e6c34..62debe46 100644 --- a/website/src/components/table-of-contents.js +++ b/website/src/components/table-of-contents.js @@ -29,7 +29,7 @@ const TocLink = styled.a` * * https://github.com/gatsbyjs/gatsby/issues/5436 */ -const TableOfContents = () => { +function TableOfContents() { const [headings, setHeadings] = useState([]); useEffect(() => { @@ -57,6 +57,6 @@ const TableOfContents = () => { ) ); -}; +} export default TableOfContents; diff --git a/website/src/components/twitter-meta.js b/website/src/components/twitter-meta.js index 80ad84d4..951b6250 100644 --- a/website/src/components/twitter-meta.js +++ b/website/src/components/twitter-meta.js @@ -1,15 +1,17 @@ import React from 'react'; import { Helmet } from 'react-helmet'; -const TwitterMeta = ({ title, description, image, imageAlt }) => ( - - - - {title && } - {description && } - {image && } - {image && imageAlt && } - -); +function TwitterMeta({ title, description, image, imageAlt }) { + return ( + + + + {title && } + {description && } + {image && } + {image && imageAlt && } + + ); +} export default TwitterMeta; diff --git a/website/src/components/video-embed.js b/website/src/components/video-embed.js index ae066849..43028d28 100644 --- a/website/src/components/video-embed.js +++ b/website/src/components/video-embed.js @@ -64,20 +64,24 @@ const VideoButton = styled.div` * We should be able to import complete inline svg's rather than base64, this * component is a stopgap for now. Source in '../img/play.svg'. */ -const PlayIcon = ({ className }) => ( - - - -); +function PlayIcon({ className }) { + return ( + + + + ); +} -const VideoEmbed = () => { +function VideoEmbed() { const [toggled, setToggled] = useState(false); - const toggleVideo = () => setToggled(true); + function toggleVideo() { + return setToggled(true); + } const embedcode = (