Skip to content

Commit 91c4180

Browse files
committed
Refactor
1 parent 19ed938 commit 91c4180

3 files changed

Lines changed: 174 additions & 124 deletions

File tree

Lines changed: 70 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,23 @@
11
import { getPathInfo } from '@sveltia/utils/file';
22
import { compare, stripSlashes } from '@sveltia/utils/string';
3-
import { getI18nConfig } from '$lib/services/contents/i18n';
43

54
/**
6-
* @import {
7-
* AssetFolderInfo,
8-
* EntryFolderInfo,
9-
* InternalLocaleCode,
10-
* InternalSiteConfig,
11-
* } from '$lib/types/private';
5+
* @import { AssetFolderInfo, InternalSiteConfig } from '$lib/types/private';
6+
* @import { CollectionFile } from '$lib/types/public';
127
*/
138

149
/**
15-
* Get all entry folders.
16-
* @param {InternalSiteConfig} config Site configuration.
17-
* @returns {EntryFolderInfo[]} Entry folders.
10+
* @typedef {object} GlobalFolders
11+
* @property {string} globalMediaFolder Normalized global `media_folder` option.
12+
* @property {string} globalPublicFolder Normalized global `public_folder` option.
1813
*/
19-
export const getAllEntryFolders = ({ collections }) => {
20-
const entryCollectionFolders = collections
21-
.filter(({ folder }) => typeof folder === 'string')
22-
.map((collection) => {
23-
const { name: collectionName, folder } = collection;
24-
const folderPath = stripSlashes(/** @type {string} */ (folder));
25-
const { i18nEnabled, structure, allLocales } = getI18nConfig(collection);
26-
const i18nRootMultiFolder = i18nEnabled && structure === 'multiple_folders_i18n_root';
27-
28-
return {
29-
collectionName,
30-
folderPath,
31-
folderPathMap: Object.fromEntries(
32-
allLocales.map((locale) => [
33-
locale,
34-
i18nRootMultiFolder ? `${locale}/${folderPath}` : folderPath,
35-
]),
36-
),
37-
};
38-
})
39-
.sort((a, b) => compare(a.folderPath ?? '', b.folderPath ?? ''));
40-
41-
const fileCollectionFolders = collections
42-
.filter(({ files }) => Array.isArray(files))
43-
.map((collection) => {
44-
const { name: collectionName, files } = collection;
45-
46-
return (files ?? []).map((file) => {
47-
/** @type {Record<InternalLocaleCode, string>} */
48-
const filePathMap = (() => {
49-
const path = stripSlashes(file.file);
50-
51-
if (!path.includes('{{locale}}')) {
52-
return { _default: path };
53-
}
54-
55-
const _i18n = getI18nConfig(collection, file);
56-
const { allLocales, defaultLocale, omitDefaultLocaleFromFileName } = _i18n;
5714

58-
return Object.fromEntries(
59-
allLocales.map((locale) => [
60-
locale,
61-
omitDefaultLocaleFromFileName && locale === defaultLocale
62-
? path.replace('.{{locale}}', '')
63-
: path.replace('{{locale}}', locale),
64-
]),
65-
);
66-
})();
67-
68-
return {
69-
collectionName,
70-
fileName: file.name,
71-
filePathMap,
72-
};
73-
});
74-
})
75-
.flat(1)
76-
.sort((a, b) => compare(Object.values(a.filePathMap)[0], Object.values(b.filePathMap)[0]));
77-
78-
return [...entryCollectionFolders, ...fileCollectionFolders];
79-
};
15+
/**
16+
* Collection-level and file-level asset folders.
17+
* @type {AssetFolderInfo[]}
18+
* @see https://decapcms.org/docs/collection-folder/#media-and-public-folder
19+
*/
20+
const assetFolders = [];
8021

8122
/**
8223
* Replace `{{media_folder}}` and `{{public_folder}}` template tags.
@@ -103,8 +44,7 @@ const replaceTags = (folder, { globalMediaFolder, globalPublicFolder }) =>
10344
* collection file.
10445
* @param {string | undefined} args.baseFolder `folder` option for the collection or base directory
10546
* of the collection file.
106-
* @param {string} args.globalMediaFolder Normalized global `media_folder` option.
107-
* @param {string} args.globalPublicFolder Normalized global `public_folder` option.
47+
* @param {GlobalFolders} args.globalFolders Global folders information.
10848
* @returns {AssetFolderInfo} Normalized asset folder information.
10949
*/
11050
const normalizeAssetFolder = ({
@@ -113,11 +53,8 @@ const normalizeAssetFolder = ({
11353
mediaFolder,
11454
publicFolder,
11555
baseFolder,
116-
globalMediaFolder,
117-
globalPublicFolder,
56+
globalFolders,
11857
}) => {
119-
const globalFolders = { globalMediaFolder, globalPublicFolder };
120-
12158
mediaFolder = replaceTags(mediaFolder, globalFolders);
12259
publicFolder =
12360
publicFolder !== undefined ? replaceTags(publicFolder, globalFolders) : mediaFolder;
@@ -139,6 +76,57 @@ const normalizeAssetFolder = ({
13976
};
14077
};
14178

79+
/**
80+
* Add an asset folder for a collection or collection file if it’s not the same as the global
81+
* asset folder.
82+
* @param {any} args Arguments for {@link normalizeAssetFolder}.
83+
*/
84+
const addFolderIfNeeded = (args) => {
85+
if (args.mediaFolder === undefined) {
86+
return;
87+
}
88+
89+
const folder = normalizeAssetFolder(args);
90+
const { globalMediaFolder, globalPublicFolder } = args.globalFolders;
91+
92+
if (
93+
!folder.entryRelative &&
94+
folder.internalPath === globalMediaFolder &&
95+
folder.publicPath === globalPublicFolder
96+
) {
97+
return;
98+
}
99+
100+
assetFolders.push(folder);
101+
};
102+
103+
/**
104+
* Iterate through files in a file collection and add their folders.
105+
* @param {object} args Arguments.
106+
* @param {string} args.collectionName Collection name.
107+
* @param {CollectionFile[]} args.files Files in a file collection.
108+
* @param {GlobalFolders} args.globalFolders Global folders information.
109+
*/
110+
const iterateFiles = ({ collectionName, files, globalFolders }) => {
111+
files.forEach((file) => {
112+
const {
113+
name: fileName,
114+
file: filePath,
115+
media_folder: fileMediaFolder,
116+
public_folder: filePublicFolder,
117+
} = file;
118+
119+
addFolderIfNeeded({
120+
collectionName,
121+
fileName,
122+
mediaFolder: fileMediaFolder,
123+
publicFolder: filePublicFolder,
124+
baseFolder: getPathInfo(filePath).dirname,
125+
globalFolders,
126+
});
127+
});
128+
};
129+
142130
/**
143131
* Get all asset folders.
144132
* @param {InternalSiteConfig} config Site configuration.
@@ -178,35 +166,7 @@ export const getAllAssetFolders = (config) => {
178166
hasTemplateTags: false,
179167
};
180168

181-
/**
182-
* Collection-level and file-level asset folders.
183-
* @type {AssetFolderInfo[]}
184-
* @see https://decapcms.org/docs/collection-folder/#media-and-public-folder
185-
*/
186-
const assetFolders = [];
187-
188-
/**
189-
* Add an asset folder for a collection or collection file if it’s not the same as the global
190-
* asset folder.
191-
* @param {any} args Arguments for {@link normalizeAssetFolder}.
192-
*/
193-
const addFolderIfNeeded = (args) => {
194-
if (args.mediaFolder === undefined) {
195-
return;
196-
}
197-
198-
const folder = normalizeAssetFolder(args);
199-
200-
if (
201-
!folder.entryRelative &&
202-
folder.internalPath === globalMediaFolder &&
203-
folder.publicPath === globalPublicFolder
204-
) {
205-
return;
206-
}
207-
208-
assetFolders.push(folder);
209-
};
169+
const globalFolders = { globalMediaFolder, globalPublicFolder };
210170

211171
collections.forEach((collection) => {
212172
const {
@@ -228,33 +188,20 @@ export const getAllAssetFolders = (config) => {
228188
return;
229189
}
230190

231-
const normalizeFolderArgs = { collectionName, globalMediaFolder, globalPublicFolder };
232191
// When specifying a `path` on an entry collection, `media_folder` defaults to an empty string
233192
const mediaFolder = _mediaFolder === undefined && entryPath !== undefined ? '' : _mediaFolder;
234193

235194
addFolderIfNeeded({
236-
...normalizeFolderArgs,
195+
collectionName,
237196
mediaFolder,
238197
publicFolder,
239198
baseFolder,
199+
globalFolders,
240200
});
241201

242-
collectionFiles?.forEach((file) => {
243-
const {
244-
name: fileName,
245-
file: filePath,
246-
media_folder: fileMediaFolder,
247-
public_folder: filePublicFolder,
248-
} = file;
249-
250-
addFolderIfNeeded({
251-
...normalizeFolderArgs,
252-
fileName,
253-
mediaFolder: fileMediaFolder,
254-
publicFolder: filePublicFolder,
255-
baseFolder: getPathInfo(filePath).dirname,
256-
});
257-
});
202+
if (collectionFiles?.length) {
203+
iterateFiles({ collectionName, files: collectionFiles, globalFolders });
204+
}
258205
});
259206

260207
assetFolders.sort((a, b) => compare(a.internalPath ?? '', b.internalPath ?? ''));
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { compare, stripSlashes } from '@sveltia/utils/string';
2+
import { getI18nConfig } from '$lib/services/contents/i18n';
3+
4+
/**
5+
* @import { EntryFolderInfo, InternalLocaleCode, InternalSiteConfig } from '$lib/types/private';
6+
* @import { Collection, CollectionFile } from '$lib/types/public';
7+
*/
8+
9+
/**
10+
* Get a collection file folder information.
11+
* @param {Collection} collection Collection.
12+
* @param {CollectionFile} file Collection file.
13+
* @returns {EntryFolderInfo} Collection file folder information.
14+
*/
15+
const getCollectionFileFolder = (collection, file) => {
16+
/** @type {Record<InternalLocaleCode, string>} */
17+
const filePathMap = (() => {
18+
const path = stripSlashes(file.file);
19+
20+
if (!path.includes('{{locale}}')) {
21+
return { _default: path };
22+
}
23+
24+
const _i18n = getI18nConfig(collection, file);
25+
const { allLocales, defaultLocale, omitDefaultLocaleFromFileName } = _i18n;
26+
27+
return Object.fromEntries(
28+
allLocales.map((locale) => [
29+
locale,
30+
omitDefaultLocaleFromFileName && locale === defaultLocale
31+
? path.replace('.{{locale}}', '')
32+
: path.replace('{{locale}}', locale),
33+
]),
34+
);
35+
})();
36+
37+
return {
38+
collectionName: collection.name,
39+
fileName: file.name,
40+
filePathMap,
41+
};
42+
};
43+
44+
/**
45+
* Compare two entry folders by their file paths. This is used to sort entry folders.
46+
* @param {EntryFolderInfo} a One entry folder.
47+
* @param {EntryFolderInfo} b Another entry folder.
48+
* @returns {number} Comparison result.
49+
*/
50+
const compareFilePath = (a, b) =>
51+
compare(Object.values(a.filePathMap ?? {})[0], Object.values(b.filePathMap ?? {})[0]);
52+
53+
/**
54+
* Get entry collection folders.
55+
* @param {InternalSiteConfig} config Site configuration.
56+
* @returns {EntryFolderInfo[]} Entry folders.
57+
*/
58+
const getEntryCollectionFolders = ({ collections }) =>
59+
collections
60+
.filter(({ folder }) => typeof folder === 'string')
61+
.map((collection) => {
62+
const { name: collectionName, folder } = collection;
63+
const folderPath = stripSlashes(/** @type {string} */ (folder));
64+
const { i18nEnabled, structure, allLocales } = getI18nConfig(collection);
65+
const i18nRootMultiFolder = i18nEnabled && structure === 'multiple_folders_i18n_root';
66+
67+
return {
68+
collectionName,
69+
folderPath,
70+
folderPathMap: Object.fromEntries(
71+
allLocales.map((locale) => [
72+
locale,
73+
i18nRootMultiFolder ? `${locale}/${folderPath}` : folderPath,
74+
]),
75+
),
76+
};
77+
})
78+
.sort((a, b) => compare(a.folderPath ?? '', b.folderPath ?? ''));
79+
80+
/**
81+
* Get file collection folders.
82+
* @param {InternalSiteConfig} config Site configuration.
83+
* @returns {EntryFolderInfo[]} Entry folders.
84+
*/
85+
const getFileCollectionFolders = ({ collections }) =>
86+
collections
87+
.filter(({ files }) => Array.isArray(files))
88+
.map((collection) =>
89+
(collection.files ?? []).map((file) => getCollectionFileFolder(collection, file)),
90+
)
91+
.flat(1)
92+
.sort(compareFilePath);
93+
94+
/**
95+
* Get all entry folders.
96+
* @param {InternalSiteConfig} config Site configuration.
97+
* @returns {EntryFolderInfo[]} Entry folders.
98+
*/
99+
export const getAllEntryFolders = (config) => [
100+
...getEntryCollectionFolders(config),
101+
...getFileCollectionFolders(config),
102+
];

src/lib/services/config/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { _ } from 'svelte-i18n';
77
import YAML from 'yaml';
88
import { allAssetFolders } from '$lib/services/assets';
99
import { gitBackendServices, validBackendNames } from '$lib/services/backends';
10-
import { getAllAssetFolders, getAllEntryFolders } from '$lib/services/config/folders';
10+
import { getAllAssetFolders } from '$lib/services/config/folders/assets';
11+
import { getAllEntryFolders } from '$lib/services/config/folders/entries';
1112
import { fetchSiteConfig } from '$lib/services/config/loader';
1213
import { allEntryFolders } from '$lib/services/contents';
1314
import { prefs } from '$lib/services/user/prefs';

0 commit comments

Comments
 (0)