fix: media public path conversion (#1003)
This commit is contained in:
parent
13f42e052a
commit
b63f5eec35
@ -6,6 +6,7 @@ import isError from 'lodash/isError';
|
||||
import uniq from 'lodash/uniq';
|
||||
import { dirname } from 'path';
|
||||
|
||||
import { DRAFT_MEDIA_FILES } from './constants/mediaLibrary';
|
||||
import { resolveFormat } from './formats/formats';
|
||||
import { commitMessageFormatter, slugFormatter } from './lib/formatters';
|
||||
import {
|
||||
@ -44,7 +45,7 @@ import {
|
||||
selectMediaFolders,
|
||||
} from './lib/util/collection.util';
|
||||
import filterEntries from './lib/util/filter.util';
|
||||
import { DRAFT_MEDIA_FILES, selectMediaFilePublicPath } from './lib/util/media.util';
|
||||
import { selectMediaFilePublicPath } from './lib/util/media.util';
|
||||
import { selectCustomPath, slugFromCustomPath } from './lib/util/nested.util';
|
||||
import { isNullish } from './lib/util/null.util';
|
||||
import { fileSearch, sortByScore } from './lib/util/search.util';
|
||||
|
@ -6,3 +6,5 @@ export const MEDIA_CARD_MARGIN = 10;
|
||||
export const MEDIA_LIBRARY_PADDING = 20;
|
||||
|
||||
export const MAX_LINK_DISPLAY_LENGTH = 28;
|
||||
|
||||
export const DRAFT_MEDIA_FILES = 'DRAFT_MEDIA_FILES';
|
||||
|
@ -149,8 +149,8 @@ export function summaryFormatter<EF extends BaseField>(
|
||||
if (entry.updatedOn && !selectField(collection, COMMIT_DATE)) {
|
||||
entryData = set(entryData, COMMIT_DATE, entry.updatedOn);
|
||||
}
|
||||
const summary = compileStringTemplate(summaryTemplate, date, slug, entryData);
|
||||
return summary;
|
||||
|
||||
return compileStringTemplate(summaryTemplate, date, slug, entryData);
|
||||
}
|
||||
|
||||
export function folderFormatter<EF extends BaseField>(
|
||||
|
@ -473,7 +473,6 @@ describe('media.util', () => {
|
||||
'path/to/media/folder/image.png',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
),
|
||||
).toBe('path/to/public/folder/image.png');
|
||||
});
|
||||
@ -491,7 +490,6 @@ describe('media.util', () => {
|
||||
'path/to/media/folder/image.png',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
),
|
||||
).toBe('/path/to/media/folder/image.png');
|
||||
});
|
||||
@ -607,6 +605,80 @@ describe('media.util', () => {
|
||||
).toBe('path/to/collection/media/folder/image.png');
|
||||
});
|
||||
|
||||
it('should handle folder collections path', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '',
|
||||
public_folder: '',
|
||||
path: '{{slug}}/index',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'base/folder/i-am-a-title/image.png',
|
||||
{
|
||||
...mockBaseEntry,
|
||||
path: 'base/folder/i-am-a-title/index.md',
|
||||
},
|
||||
mockImageField,
|
||||
),
|
||||
).toBe('image.png');
|
||||
});
|
||||
|
||||
it('should handle folder collections path for new entry', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '',
|
||||
public_folder: '',
|
||||
path: '{{slug}}/index',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'base/folder/DRAFT_MEDIA_FILES/image.png',
|
||||
{
|
||||
...mockBaseEntry,
|
||||
path: '',
|
||||
},
|
||||
mockImageField,
|
||||
),
|
||||
).toBe('image.png');
|
||||
});
|
||||
|
||||
describe('template variable', () => {
|
||||
it('should substitute field value', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
@ -720,7 +792,7 @@ describe('media.util', () => {
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'/path/to/media/folder/i-am-a-title-fish/image.png',
|
||||
'path/to/media/folder/i-am-a-title-fish/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
),
|
||||
@ -1097,5 +1169,795 @@ describe('media.util', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with folder support', () => {
|
||||
const mockBaseCollection = createMockCollection<UnknownField>({
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const mockBaseEntry = createMockEntry({
|
||||
path: 'path/to/entry/index.md',
|
||||
data: {
|
||||
title: 'I am a title',
|
||||
},
|
||||
});
|
||||
|
||||
describe('top level', () => {
|
||||
it('should default to top level config public_folder', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [mockBaseCollection],
|
||||
media_folder: 'path/to/media/folder',
|
||||
public_folder: 'path/to/public/folder',
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
undefined,
|
||||
'path/to/media/folder/current/folder/image.png',
|
||||
undefined,
|
||||
undefined,
|
||||
'path/to/media/folder/current/folder',
|
||||
),
|
||||
).toBe('path/to/public/folder/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should use media_folder as an absolute path if public_folder is not provided', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [mockBaseCollection],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
undefined,
|
||||
'path/to/media/folder/current/folder/image.png',
|
||||
undefined,
|
||||
undefined,
|
||||
'path/to/media/folder/current/folder',
|
||||
),
|
||||
).toBe('/path/to/media/folder/current/folder/image.png');
|
||||
});
|
||||
});
|
||||
|
||||
describe('entry', () => {
|
||||
it('should default to top level config public_folder', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [mockBaseCollection],
|
||||
media_folder: 'path/to/media/folder',
|
||||
public_folder: 'path/to/public/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/media/folder/current/folder/image.png',
|
||||
mockBaseEntry,
|
||||
mockImageField,
|
||||
'path/to/media/folder/current/folder',
|
||||
),
|
||||
).toBe('path/to/public/folder/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should default to top level config media_folder as an absolute path', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [mockBaseCollection],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/media/folder/current/folder/image.png',
|
||||
mockBaseEntry,
|
||||
mockImageField,
|
||||
'path/to/media/folder/current/folder',
|
||||
),
|
||||
).toBe('/path/to/media/folder/current/folder/image.png');
|
||||
});
|
||||
|
||||
describe('relative path', () => {
|
||||
it('should handle folder collections path', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '',
|
||||
public_folder: '',
|
||||
path: '{{slug}}/index',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/folder/current/folder/image.png',
|
||||
{
|
||||
...mockBaseEntry,
|
||||
path: 'path/to/folder/index.md',
|
||||
},
|
||||
mockImageField,
|
||||
'path/to/folder/current/folder',
|
||||
),
|
||||
).toBe('current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should handle folder collections path for new entry', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '',
|
||||
public_folder: '',
|
||||
path: '{{slug}}/index',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'base/folder/DRAFT_MEDIA_FILES/current/folder/image.png',
|
||||
{
|
||||
...mockBaseEntry,
|
||||
path: '',
|
||||
},
|
||||
mockImageField,
|
||||
'base/folder/DRAFT_MEDIA_FILES/current/folder',
|
||||
),
|
||||
).toBe('current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should use collection public_folder if available', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: 'path/to/collection/media/folder',
|
||||
public_folder: 'path/to/collection/public/folder',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/collection/media/folder/current/folder/image.png',
|
||||
mockBaseEntry,
|
||||
mockImageField,
|
||||
'path/to/collection/media/folder/current/folder',
|
||||
),
|
||||
).toBe('path/to/collection/public/folder/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should use collection media_folder if no public_folder is available', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: 'path/to/collection/media/folder',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/collection/media/folder/current/folder/image.png',
|
||||
mockBaseEntry,
|
||||
mockImageField,
|
||||
'path/to/collection/media/folder/current/folder',
|
||||
),
|
||||
).toBe('path/to/collection/media/folder/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should handle folder collections path', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '',
|
||||
public_folder: '',
|
||||
path: '{{slug}}/index',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'base/folder/i-am-a-title/current/folder/image.png',
|
||||
{
|
||||
...mockBaseEntry,
|
||||
path: 'base/folder/i-am-a-title/index.md',
|
||||
},
|
||||
mockImageField,
|
||||
'base/folder/i-am-a-title/current/folder',
|
||||
),
|
||||
).toBe('current/folder/image.png');
|
||||
});
|
||||
|
||||
describe('template variable', () => {
|
||||
it('should substitute field value', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: 'path/to/some/other/media/{{fields.title}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/some/other/media/i-am-a-title/current/folder/image.png',
|
||||
mockBaseEntry,
|
||||
mockImageField,
|
||||
'path/to/some/other/media/i-am-a-title/current/folder',
|
||||
),
|
||||
).toBe('path/to/some/other/media/i-am-a-title/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should substitute slug', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: 'path/to/some/other/media/{{slug}}',
|
||||
slug: '{{fields.title}}-{{fields.name}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
widget: 'string',
|
||||
},
|
||||
mockBaseImageField,
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
const mockEntry = createMockEntry({
|
||||
path: 'path/to/entry/index.md',
|
||||
slug: 'i-am-a-title-fish',
|
||||
data: { title: 'i am a title', name: 'fish' },
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/some/other/media/i-am-a-title-fish/current/folder/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
'path/to/some/other/media/i-am-a-title-fish/current/folder',
|
||||
),
|
||||
).toBe('path/to/some/other/media/i-am-a-title-fish/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should substitute slug from top level media_folder if no public_folders', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
slug: '{{fields.title}}-{{fields.name}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
widget: 'string',
|
||||
},
|
||||
mockBaseImageField,
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder/{{slug}}',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
const mockEntry = createMockEntry({
|
||||
path: 'path/to/entry/index.md',
|
||||
slug: 'i-am-a-title-fish',
|
||||
data: { title: 'i am a title', name: 'fish' },
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/media/folder/i-am-a-title-fish/current/folder/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
'path/to/media/folder/i-am-a-title-fish/current/folder',
|
||||
),
|
||||
).toBe('/path/to/media/folder/i-am-a-title-fish/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should substitute slug from top level public_folder', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
slug: '{{fields.title}}-{{fields.name}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
widget: 'string',
|
||||
},
|
||||
mockBaseImageField,
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder/{{slug}}',
|
||||
public_folder: 'path/to/public/folder/{{slug}}',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
const mockEntry = createMockEntry({
|
||||
path: 'path/to/entry/index.md',
|
||||
slug: 'i-am-a-title-fish',
|
||||
data: { title: 'i am a title', name: 'fish' },
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/media/folder/i-am-a-title-fish/current/folder/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
'path/to/media/folder/i-am-a-title-fish/current/folder',
|
||||
),
|
||||
).toBe('path/to/public/folder/i-am-a-title-fish/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should not throw error when evaluating slug for new entry', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: 'path/to/collection/media/folder/{{slug}}',
|
||||
public_folder: 'path/to/collection/public/folder/{{slug}}',
|
||||
slug: '{{fields.title}}-{{fields.name}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
widget: 'string',
|
||||
},
|
||||
mockBaseImageField,
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
const mockEntry = createMockEntry({
|
||||
path: 'path/to/entry/index.md',
|
||||
slug: '',
|
||||
data: {},
|
||||
newRecord: true,
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/collection/media/folder/current/folder/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
'path/to/collection/media/folder/current/folder',
|
||||
),
|
||||
).toBe('path/to/collection/public/folder/current/folder/image.png');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('absolute path', () => {
|
||||
it('should use collection public_folder if available', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: 'path/to/collection/media/folder',
|
||||
public_folder: '/path/to/collection/public/folder',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'path/to/collection/media/folder/current/folder/image.png',
|
||||
mockBaseEntry,
|
||||
mockImageField,
|
||||
'path/to/collection/media/folder/current/folder',
|
||||
),
|
||||
).toBe('/path/to/collection/public/folder/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should use collection media_folder if no public_folder is available', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '/path/to/collection/media/folder',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'/path/to/collection/media/folder/current/folder/image.png',
|
||||
mockBaseEntry,
|
||||
mockImageField,
|
||||
'/path/to/collection/media/folder/current/folder',
|
||||
),
|
||||
).toBe('/path/to/collection/media/folder/current/folder/image.png');
|
||||
});
|
||||
|
||||
describe('template variable', () => {
|
||||
it('should substitute field value', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '/path/to/some/other/media/{{fields.title}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'/path/to/some/other/media/i-am-a-title/current/folder/image.png',
|
||||
mockBaseEntry,
|
||||
mockImageField,
|
||||
'/path/to/some/other/media/i-am-a-title/current/folder',
|
||||
),
|
||||
).toBe('/path/to/some/other/media/i-am-a-title/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should substitute slug', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '/path/to/some/other/media/{{slug}}',
|
||||
slug: '{{fields.title}}-{{fields.name}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
widget: 'string',
|
||||
},
|
||||
mockBaseImageField,
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
const mockEntry = createMockEntry({
|
||||
path: 'path/to/entry/index.md',
|
||||
slug: 'i-am-a-title-fish',
|
||||
data: { title: 'i am a title', name: 'fish' },
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'/path/to/some/other/media/i-am-a-title-fish/current/folder/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
'/path/to/some/other/media/i-am-a-title-fish/current/folder',
|
||||
),
|
||||
).toBe('/path/to/some/other/media/i-am-a-title-fish/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should substitute slug from top level media_folder if no public_folders', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
slug: '{{fields.title}}-{{fields.name}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
widget: 'string',
|
||||
},
|
||||
mockBaseImageField,
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: '/path/to/media/folder/{{slug}}',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
const mockEntry = createMockEntry({
|
||||
path: 'path/to/entry/index.md',
|
||||
slug: 'i-am-a-title-fish',
|
||||
data: { title: 'i am a title', name: 'fish' },
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'/path/to/media/folder/i-am-a-title-fish/current/folder/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
'/path/to/media/folder/i-am-a-title-fish/current/folder',
|
||||
),
|
||||
).toBe('/path/to/media/folder/i-am-a-title-fish/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should substitute slug from top level public_folder', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
slug: '{{fields.title}}-{{fields.name}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
widget: 'string',
|
||||
},
|
||||
mockBaseImageField,
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: '/path/to/media/folder/{{slug}}',
|
||||
public_folder: '/path/to/public/folder/{{slug}}',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
const mockEntry = createMockEntry({
|
||||
path: 'path/to/entry/index.md',
|
||||
slug: 'i-am-a-title-fish',
|
||||
data: { title: 'i am a title', name: 'fish' },
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'/path/to/media/folder/i-am-a-title-fish/current/folder/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
'/path/to/media/folder/i-am-a-title-fish/current/folder',
|
||||
),
|
||||
).toBe('/path/to/public/folder/i-am-a-title-fish/current/folder/image.png');
|
||||
});
|
||||
|
||||
it('should not throw error when evaluating slug for new entry', () => {
|
||||
const mockConfig = createMockConfig({
|
||||
collections: [
|
||||
createMockCollection<UnknownField>({
|
||||
folder: 'base/folder',
|
||||
media_folder: '/path/to/collection/media/folder/{{slug}}',
|
||||
public_folder: '/path/to/collection/public/folder/{{slug}}',
|
||||
slug: '{{fields.title}}-{{fields.name}}',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
widget: 'string',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
widget: 'string',
|
||||
},
|
||||
mockBaseImageField,
|
||||
],
|
||||
}),
|
||||
],
|
||||
media_folder: 'path/to/media/folder',
|
||||
});
|
||||
|
||||
const mockCollection = mockConfig.collections[0];
|
||||
const mockImageField = (mockConfig.collections[0] as FolderCollection)
|
||||
.fields[3] as FileOrImageField;
|
||||
|
||||
const mockEntry = createMockEntry({
|
||||
path: 'path/to/entry/DRAFT_MEDIA_FILES/index.md',
|
||||
slug: '',
|
||||
data: {},
|
||||
newRecord: true,
|
||||
});
|
||||
|
||||
expect(
|
||||
selectMediaFilePublicPath(
|
||||
mockConfig,
|
||||
mockCollection,
|
||||
'/path/to/collection/media/folder/DRAFT_MEDIA_FILES/current/folder/image.png',
|
||||
mockEntry,
|
||||
mockImageField,
|
||||
'/path/to/collection/media/folder/DRAFT_MEDIA_FILES/current/folder',
|
||||
),
|
||||
).toBe(
|
||||
'/path/to/collection/public/folder/DRAFT_MEDIA_FILES/current/folder/image.png',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,14 +1,25 @@
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { dirname } from 'path';
|
||||
|
||||
import { isNotNullish } from './null.util';
|
||||
import { DRAFT_MEDIA_FILES } from '@staticcms/core/constants/mediaLibrary';
|
||||
import {
|
||||
I18N_FIELD_DUPLICATE,
|
||||
I18N_FIELD_TRANSLATE,
|
||||
duplicateDefaultI18nFields,
|
||||
hasI18n,
|
||||
} from '../i18n';
|
||||
import { joinUrlPath } from '../urlHelper';
|
||||
import { isNotNullish } from './null.util';
|
||||
import { isNotEmpty } from './string.util';
|
||||
|
||||
import type { Collection, EntryData, Field, ObjectValue } from '@staticcms/core/interface';
|
||||
import type {
|
||||
BaseField,
|
||||
Collection,
|
||||
Entry,
|
||||
EntryData,
|
||||
Field,
|
||||
ObjectValue,
|
||||
} from '@staticcms/core/interface';
|
||||
|
||||
export function applyDefaultsToDraftData(
|
||||
fields: Field[],
|
||||
@ -73,3 +84,18 @@ export function createEmptyDraftI18nData(collection: Collection, dataFields: Fie
|
||||
const i18nData = createEmptyDraftData(dataFields, skipField);
|
||||
return duplicateDefaultI18nFields(collection, i18nData);
|
||||
}
|
||||
|
||||
export function createEntryMediaPath<EF extends BaseField>(
|
||||
entry: Entry | null | undefined,
|
||||
collection: Collection<EF> | null | undefined,
|
||||
folder: string,
|
||||
) {
|
||||
const entryPath = entry?.path;
|
||||
return isNotEmpty(entryPath)
|
||||
? joinUrlPath(dirname(entryPath), folder)
|
||||
: joinUrlPath(
|
||||
collection && 'folder' in collection ? collection.folder : '',
|
||||
DRAFT_MEDIA_FILES,
|
||||
folder,
|
||||
);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { dirname } from 'path';
|
||||
import { basename, isAbsolutePath } from '.';
|
||||
import { folderFormatter } from '../formatters';
|
||||
import { joinUrlPath } from '../urlHelper';
|
||||
import { createEntryMediaPath } from './entry.util';
|
||||
|
||||
import type {
|
||||
BaseField,
|
||||
@ -19,8 +20,6 @@ import type {
|
||||
ObjectField,
|
||||
} from '@staticcms/core/interface';
|
||||
|
||||
export const DRAFT_MEDIA_FILES = 'DRAFT_MEDIA_FILES';
|
||||
|
||||
function getFileField<EF extends BaseField>(
|
||||
collectionFiles: CollectionFile<EF>[],
|
||||
slug: string | undefined,
|
||||
@ -228,13 +227,13 @@ function traverseFields<EF extends BaseField>(
|
||||
export function selectMediaFolder<EF extends BaseField>(
|
||||
config: Config<EF>,
|
||||
collection: Collection<EF> | undefined | null,
|
||||
entryMap: Entry | undefined | null,
|
||||
entry: Entry | undefined | null,
|
||||
field: MediaField | undefined,
|
||||
currentFolder?: string,
|
||||
) {
|
||||
let mediaFolder = folderFormatter(
|
||||
config.media_folder ?? '',
|
||||
entryMap,
|
||||
entry,
|
||||
collection as Collection,
|
||||
config.media_folder ?? '',
|
||||
'media_folder',
|
||||
@ -243,19 +242,12 @@ export function selectMediaFolder<EF extends BaseField>(
|
||||
|
||||
if (currentFolder) {
|
||||
mediaFolder = currentFolder;
|
||||
} else if (hasCustomFolder('media_folder', collection, entryMap?.slug, field)) {
|
||||
const folder = evaluateFolder('media_folder', config, collection!, entryMap, field);
|
||||
} else if (hasCustomFolder('media_folder', collection, entry?.slug, field)) {
|
||||
const folder = evaluateFolder('media_folder', config, collection!, entry, field);
|
||||
if (folder.startsWith('/')) {
|
||||
mediaFolder = folder.replace(/^[/]*/g, '');
|
||||
} else {
|
||||
const entryPath = entryMap?.path;
|
||||
mediaFolder = entryPath
|
||||
? joinUrlPath(dirname(entryPath), folder)
|
||||
: joinUrlPath(
|
||||
collection && 'folder' in collection ? collection.folder : '',
|
||||
DRAFT_MEDIA_FILES,
|
||||
folder,
|
||||
);
|
||||
mediaFolder = createEntryMediaPath(entry, collection, folder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +258,7 @@ export function selectMediaFilePublicPath<EF extends BaseField>(
|
||||
config: Config<EF>,
|
||||
collection: Collection<EF> | undefined | null,
|
||||
mediaPath: string,
|
||||
entryMap: Entry | undefined | null,
|
||||
entry: Entry | undefined | null,
|
||||
field: MediaField | undefined,
|
||||
currentFolder?: string,
|
||||
) {
|
||||
@ -276,7 +268,7 @@ export function selectMediaFilePublicPath<EF extends BaseField>(
|
||||
|
||||
let publicFolder = folderFormatter(
|
||||
config.public_folder ?? '',
|
||||
entryMap,
|
||||
entry,
|
||||
collection as Collection,
|
||||
config.public_folder ?? '',
|
||||
'public_folder',
|
||||
@ -285,38 +277,35 @@ export function selectMediaFilePublicPath<EF extends BaseField>(
|
||||
|
||||
let mediaFolder = folderFormatter(
|
||||
config.media_folder ?? '',
|
||||
entryMap,
|
||||
entry,
|
||||
collection as Collection,
|
||||
config.media_folder ?? '',
|
||||
'media_folder',
|
||||
config.slug,
|
||||
);
|
||||
|
||||
let selectedPublicFolder = publicFolder;
|
||||
let selectedMediaFolder = mediaFolder;
|
||||
|
||||
const customPublicFolder = hasCustomFolder('public_folder', collection, entryMap?.slug, field);
|
||||
const customMediaFolder = hasCustomFolder('media_folder', collection, entryMap?.slug, field);
|
||||
const customPublicFolder = hasCustomFolder('public_folder', collection, entry?.slug, field);
|
||||
const customMediaFolder = hasCustomFolder('media_folder', collection, entry?.slug, field);
|
||||
|
||||
if (customPublicFolder) {
|
||||
publicFolder = evaluateFolder('public_folder', config, collection!, entryMap, field);
|
||||
selectedPublicFolder = publicFolder;
|
||||
publicFolder = evaluateFolder('public_folder', config, collection!, entry, field);
|
||||
}
|
||||
|
||||
if (customMediaFolder) {
|
||||
mediaFolder = evaluateFolder('media_folder', config, collection!, entryMap, field);
|
||||
selectedMediaFolder = mediaFolder;
|
||||
mediaFolder = evaluateFolder('media_folder', config, collection!, entry, field);
|
||||
}
|
||||
|
||||
if (publicFolder === '' && mediaFolder === '' && collection && 'folder' in collection) {
|
||||
mediaFolder = createEntryMediaPath(entry, collection, mediaFolder);
|
||||
}
|
||||
|
||||
if (currentFolder) {
|
||||
const mediaFolder = customMediaFolder
|
||||
? evaluateFolder('media_folder', config, collection!, entryMap, field)
|
||||
: config['media_folder'];
|
||||
selectedPublicFolder = trim(currentFolder, '/').replace(trim(mediaFolder!, '/'), publicFolder);
|
||||
publicFolder = currentFolder.replace(mediaFolder, publicFolder);
|
||||
mediaFolder = currentFolder;
|
||||
}
|
||||
|
||||
if (mediaPath.startsWith(selectedMediaFolder)) {
|
||||
return mediaPath.replace(selectedMediaFolder, selectedPublicFolder);
|
||||
if (mediaPath.startsWith(mediaFolder)) {
|
||||
return mediaPath.replace(mediaFolder, publicFolder);
|
||||
}
|
||||
|
||||
return mediaPath;
|
||||
|
Loading…
x
Reference in New Issue
Block a user