Files
static-cms/core/src/lib/util/media.util.ts
2022-11-02 13:18:06 -04:00

296 lines
6.9 KiB
TypeScript

import { dirname, join } from 'path';
import trim from 'lodash/trim';
import { folderFormatter } from '../formatters';
import { joinUrlPath } from '../urlHelper';
import { basename, isAbsolutePath } from '.';
import type {
Config,
Field,
Collection,
CollectionFile,
Entry,
FileOrImageField,
MarkdownField,
ListField,
ObjectField,
} from '../../interface';
export const DRAFT_MEDIA_FILES = 'DRAFT_MEDIA_FILES';
function getFileField(collectionFiles: CollectionFile[], slug: string | undefined) {
const file = collectionFiles.find(f => f?.name === slug);
return file;
}
function isMediaField(
folderKey: 'media_folder' | 'public_folder',
field: Field | undefined,
): field is FileOrImageField | MarkdownField {
return Boolean(field && folderKey in field);
}
function hasCustomFolder(
folderKey: 'media_folder' | 'public_folder',
collection: Collection | undefined | null,
slug: string | undefined,
field: Field | undefined,
): field is FileOrImageField | MarkdownField {
if (!collection) {
return false;
}
if (!isMediaField(folderKey, field)) {
return false;
}
if (field[folderKey]) {
return true;
}
if (collection.files) {
const file = getFileField(collection.files, slug);
if (file && file[folderKey]) {
return true;
}
}
if (collection[folderKey]) {
return true;
}
return false;
}
function evaluateFolder(
folderKey: 'media_folder' | 'public_folder',
config: Config,
c: Collection,
entryMap: Entry | undefined,
field: FileOrImageField | MarkdownField,
) {
let currentFolder = config[folderKey]!;
const collection = { ...c };
// add identity template if doesn't exist
if (!collection[folderKey]) {
collection[folderKey] = `{{${folderKey}}}`;
}
if (collection.files) {
// files collection evaluate the collection template
// then move on to the specific file configuration denoted by the slug
currentFolder = folderFormatter(
collection[folderKey]!,
entryMap,
collection,
currentFolder,
folderKey,
config.slug,
);
const f = getFileField(collection.files!, entryMap?.slug);
if (f) {
const file = { ...f };
if (!file[folderKey]) {
// add identity template if doesn't exist
file[folderKey] = `{{${folderKey}}}`;
}
// evaluate the file template and keep evaluating until we match our field
currentFolder = folderFormatter(
file[folderKey]!,
entryMap,
collection,
currentFolder,
folderKey,
config.slug,
);
if (field) {
const fieldFolder = traverseFields(
folderKey,
config,
collection,
entryMap,
field,
file.fields! as Field[],
currentFolder,
);
if (fieldFolder !== null) {
currentFolder = fieldFolder;
}
}
}
} else {
// folder collection, evaluate the collection template
// and keep evaluating until we match our field
currentFolder = folderFormatter(
collection[folderKey]!,
entryMap,
collection,
currentFolder,
folderKey,
config.slug,
);
if (field) {
const fieldFolder = traverseFields(
folderKey,
config,
collection,
entryMap,
field,
collection.fields! as Field[],
currentFolder,
);
if (fieldFolder !== null) {
currentFolder = fieldFolder;
}
}
}
return currentFolder;
}
function traverseFields(
folderKey: 'media_folder' | 'public_folder',
config: Config,
collection: Collection,
entryMap: Entry | undefined,
field: FileOrImageField | MarkdownField | ListField | ObjectField,
fields: Field[],
currentFolder: string,
): string | null {
const matchedField = fields.filter(f => f === field)[0] as
| FileOrImageField
| MarkdownField
| ListField
| ObjectField
| undefined;
if (matchedField && isMediaField(folderKey, matchedField)) {
return folderFormatter(
matchedField[folderKey] ? matchedField[folderKey]! : `{{${folderKey}}}`,
entryMap,
collection,
currentFolder,
folderKey,
config.slug,
);
}
for (const f of fields) {
const childField: Field = { ...f };
if (isMediaField(folderKey, childField) && !childField[folderKey]) {
// add identity template if doesn't exist
childField[folderKey] = `{{${folderKey}}}`;
}
const folder = folderFormatter(
isMediaField(folderKey, childField) ? childField[folderKey] ?? '' : '',
entryMap,
collection,
currentFolder,
folderKey,
config.slug,
);
let fieldFolder = null;
if ('fields' in childField && childField.fields) {
fieldFolder = traverseFields(
folderKey,
config,
collection,
entryMap,
childField,
childField.fields,
folder,
);
} else if ('types' in childField && childField.types) {
fieldFolder = traverseFields(
folderKey,
config,
collection,
entryMap,
childField,
childField.types,
folder,
);
}
if (fieldFolder != null) {
return fieldFolder;
}
}
return null;
}
export function selectMediaFolder(
config: Config,
collection: Collection | undefined | null,
entryMap: Entry | undefined,
field: Field | undefined,
) {
const name = 'media_folder';
let mediaFolder = config[name];
if (hasCustomFolder(name, collection, entryMap?.slug, field)) {
const folder = evaluateFolder(name, config, collection!, entryMap, field);
if (folder.startsWith('/')) {
// return absolute paths as is
mediaFolder = join(folder);
} else {
const entryPath = entryMap?.path;
mediaFolder = entryPath
? join(dirname(entryPath), folder)
: join(collection!.folder as string, DRAFT_MEDIA_FILES);
}
}
return trim(mediaFolder, '/');
}
export function selectMediaFilePublicPath(
config: Config,
collection: Collection | null,
mediaPath: string,
entryMap: Entry | undefined,
field: Field | undefined,
) {
if (isAbsolutePath(mediaPath)) {
return mediaPath;
}
const name = 'public_folder';
let publicFolder = config[name]!;
const customFolder = hasCustomFolder(name, collection, entryMap?.slug, field);
if (customFolder) {
publicFolder = evaluateFolder(name, config, collection!, entryMap, field);
}
if (isAbsolutePath(publicFolder)) {
return joinUrlPath(publicFolder, basename(mediaPath));
}
return join(publicFolder, basename(mediaPath));
}
export function selectMediaFilePath(
config: Config,
collection: Collection | null,
entryMap: Entry | undefined,
mediaPath: string,
field: Field | undefined,
) {
if (isAbsolutePath(mediaPath)) {
return mediaPath;
}
const mediaFolder = selectMediaFolder(config, collection, entryMap, field);
return join(mediaFolder, basename(mediaPath));
}