1- import { Collection , Config , DataFormat , Glob , Singleton } from '../config' ;
1+ import { Config , DataFormat , Glob } from '../config' ;
22import { ComponentSchema } from '../form/api' ;
3+ import { memoize } from './memoize' ;
34
45export function fixPath ( path : string ) {
56 return path . replace ( / ^ \. ? \/ + / , '' ) . replace ( / \/ * $ / , '' ) ;
@@ -25,17 +26,11 @@ export function getCollectionPath(config: Config, collection: string) {
2526}
2627
2728export function getCollectionFormat ( config : Config , collection : string ) {
28- const collectionConfig = config . collections ! [ collection ] ;
29- return getFormatInfo ( collectionConfig ) (
30- getConfiguredCollectionPath ( config , collection )
31- ) ;
29+ return getFormatInfo ( config , 'collections' , collection ) ;
3230}
3331
3432export function getSingletonFormat ( config : Config , singleton : string ) {
35- const singletonConfig = config . singletons ! [ singleton ] ;
36- return getFormatInfo ( singletonConfig ) (
37- singletonConfig . path ?? `${ singleton } /`
38- ) ;
33+ return getFormatInfo ( config , 'singletons' , singleton ) ;
3934}
4035
4136export function getCollectionItemPath (
@@ -88,46 +83,19 @@ export function getDataFileExtension(formatInfo: FormatInfo) {
8883 : '.' + formatInfo . data ;
8984}
9085
91- function weakMemoize < Arg extends object , Return > (
92- func : ( arg : Arg ) => Return
93- ) : ( arg : Arg ) => Return {
94- const cache = new WeakMap < Arg , Return > ( ) ;
95- return ( arg : Arg ) => {
96- if ( cache . has ( arg ) ) {
97- return cache . get ( arg ) ! ;
98- }
99- const result = func ( arg ) ;
100- cache . set ( arg , result ) ;
101- return result ;
102- } ;
103- }
104-
105- function memoize < Arg , Return > (
106- func : ( arg : Arg ) => Return
107- ) : ( arg : Arg ) => Return {
108- const cache = new Map < Arg , Return > ( ) ;
109- return ( arg : Arg ) => {
110- if ( cache . has ( arg ) ) {
111- return cache . get ( arg ) ! ;
112- }
113- const result = func ( arg ) ;
114- cache . set ( arg , result ) ;
115- return result ;
116- } ;
117- }
118-
119- const getFormatInfo = weakMemoize (
120- ( collectionOrSingleton : Collection < any , any > | Singleton < any > ) => {
121- return memoize ( ( path : string ) =>
122- _getFormatInfo ( collectionOrSingleton , path )
123- ) ;
124- }
125- ) ;
86+ const getFormatInfo = memoize ( _getFormatInfo ) ;
12687
12788function _getFormatInfo (
128- collectionOrSingleton : Collection < any , any > | Singleton < any > ,
129- path : string
89+ config : Config ,
90+ type : 'collections' | 'singletons' ,
91+ key : string
13092) : FormatInfo {
93+ const collectionOrSingleton =
94+ type === 'collections' ? config . collections ! [ key ] : config . singletons ! [ key ] ;
95+ const path =
96+ type === 'collections'
97+ ? getConfiguredCollectionPath ( config , key )
98+ : collectionOrSingleton . path ?? `${ key } /` ;
13199 const dataLocation = path . endsWith ( '/' ) ? 'index' : 'outer' ;
132100 const { schema, format = 'yaml' } = collectionOrSingleton ;
133101 if ( typeof format === 'string' ) {
@@ -137,19 +105,24 @@ function _getFormatInfo(
137105 data : format ,
138106 } ;
139107 }
140- let contentField ;
108+ let contentField : FormatInfo [ 'contentField' ] ;
141109 if ( format . contentField ) {
142110 let field : ComponentSchema = { kind : 'object' as const , fields : schema } ;
143111 let path = Array . isArray ( format . contentField )
144112 ? format . contentField
145113 : [ format . contentField ] ;
146-
147- contentField = {
148- path,
149- contentExtension : getContentExtension ( path , field , ( ) =>
150- path . length === 1 ? path [ 0 ] : JSON . stringify ( path )
151- ) ,
152- } ;
114+ let contentExtension ;
115+ try {
116+ contentExtension = getContentExtension ( path , field , ( ) =>
117+ JSON . stringify ( format . contentField )
118+ ) ;
119+ } catch ( err ) {
120+ if ( err instanceof ContentFieldLocationError ) {
121+ throw new Error ( `${ err . message } (${ type } .${ key } )` ) ;
122+ }
123+ throw err ;
124+ }
125+ contentField = { path, contentExtension } ;
153126 }
154127 return {
155128 data : format . data ?? 'yaml' ,
@@ -158,29 +131,37 @@ function _getFormatInfo(
158131 } ;
159132}
160133
134+ class ContentFieldLocationError extends Error {
135+ constructor ( message : string ) {
136+ super ( message ) ;
137+ }
138+ }
139+
161140function getContentExtension (
162141 path : string [ ] ,
163142 schema : ComponentSchema ,
164143 debugName : ( ) => string
165144) : string {
166145 if ( path . length === 0 ) {
167146 if ( schema . kind !== 'form' || schema . formKind !== 'content' ) {
168- throw new Error (
147+ throw new ContentFieldLocationError (
169148 `Content field for ${ debugName ( ) } is not a content field`
170149 ) ;
171150 }
172151 return schema . contentExtension ;
173152 }
174153 if ( schema . kind === 'object' ) {
175- return getContentExtension (
176- path . slice ( 1 ) ,
177- schema . fields [ path [ 0 ] ] ,
178- debugName
179- ) ;
154+ const field = schema . fields [ path [ 0 ] ] ;
155+ if ( ! field ) {
156+ throw new ContentFieldLocationError (
157+ `Field ${ debugName ( ) } specified in contentField does not exist`
158+ ) ;
159+ }
160+ return getContentExtension ( path . slice ( 1 ) , field , debugName ) ;
180161 }
181162 if ( schema . kind === 'conditional' ) {
182163 if ( path [ 0 ] !== 'value' ) {
183- throw new Error (
164+ throw new ContentFieldLocationError (
184165 `Conditional fields referenced in a contentField path must only reference the value field (${ debugName ( ) } )`
185166 ) ;
186167 }
@@ -197,19 +178,19 @@ function getContentExtension(
197178 continue ;
198179 }
199180 if ( contentExtension !== foundContentExtension ) {
200- throw new Error (
181+ throw new ContentFieldLocationError (
201182 `contentField ${ debugName ( ) } has conflicting content extensions`
202183 ) ;
203184 }
204185 }
205186 if ( ! contentExtension ) {
206- throw new Error (
187+ throw new ContentFieldLocationError (
207188 `contentField ${ debugName ( ) } does not point to a content field`
208189 ) ;
209190 }
210191 return contentExtension ;
211192 }
212- throw new Error (
193+ throw new ContentFieldLocationError (
213194 `Path specified in contentField ${ debugName ( ) } does not point to a content field`
214195 ) ;
215196}
0 commit comments