11'use strict' ;
22
3+ /**
4+ * GulpJsonLoader
5+ *
6+ * @file
7+ * @ingroup Plugins
8+ * @version 1.2
9+ * @license MIT
10+ * @author Alexander Yukal <yukal@email.ua>
11+ */
12+
313const Util = require ( 'util' ) ;
414const Path = require ( 'path' ) ;
515const Fs = require ( 'fs' ) ;
616
717const APP_PATH = process . cwd ( ) ;
8- const DEFAULT_SOURCE_PATH = './ src' ;
18+ const DEFAULT_SOURCE_PATH = 'src' ;
919const BREAK_LINE = process . platform === 'win32' ? '\r\n' : '\n' ;
10- const ERR_TOP_DIR = 'Working with top-level directories is prohibited!' ;
20+ const ERR_EXTERNAL_PATH = 'Working with external paths is prohibited!' ;
1121
12- const CachedData = { } ;
1322const BrushColors = {
1423 red : 1 ,
1524 cyan : 6 ,
1625 grey : 8
1726} ;
1827
19- const getAbsolutePath = ( path , subdir = '' ) => {
20- if ( path . startsWith ( '/' ) ) {
21- path = '.' + path ;
22- }
23-
24- path = Path . join ( APP_PATH , path ) ;
25-
26- return subdir
27- ? Path . join ( path , subdir )
28- : path ;
29- }
30-
3128/**
3229 * brush
3330 * Adding the ANSI escape codes to a textual data
@@ -66,19 +63,36 @@ const reportAction = (ctx, pathJson, filename, action) => {
6663 process . stdout . write ( message ) ;
6764}
6865
69- const loadImportsAsync = ( ctx , imports ) => {
66+ const loadImportsAsync = ( ctx , imports , cachedData ) => {
7067 return new Promise ( ( resolve , reject ) => {
7168 if ( ! Array . isArray ( imports ) ) {
69+
7270 reject ( new Error ( 'Imports should be an Array' ) ) ;
71+
7372 } else {
74- const storage = { } ;
75- loadImportsRecursively ( { ctx, imports, storage, resolve, reject } ) ;
73+
74+ if ( imports . length < 1 ) {
75+ resolve ( { } ) ;
76+ return ;
77+ }
78+
79+ const options = { ctx, imports, cachedData, pocket : { } } ;
80+
81+ loadImportsRecursively ( options , ( error , pocket ) => {
82+ if ( error !== null ) {
83+ reject ( error ) ;
84+ return ;
85+ }
86+
87+ resolve ( pocket ) ;
88+ } ) ;
89+
7690 }
7791 } ) ;
7892} ;
7993
80- const loadImportsRecursively = async ( options ) => {
81- const { ctx, imports, storage , resolve , reject , idx = 0 } = options ;
94+ const loadImportsRecursively = async ( options , callback ) => {
95+ const { ctx, imports, cachedData , pocket , idx = 0 } = options ;
8296 const { report, pathData } = ctx ;
8397
8498 if ( idx < imports . length ) {
@@ -87,78 +101,78 @@ const loadImportsRecursively = async (options) => {
87101 const jsonRelativePath = imports [ idx ] + '.json' ;
88102 const jsonFullPath = Path . join ( pathData , 'imports' , jsonRelativePath ) ;
89103 const jsonFilename = Path . basename ( jsonFullPath , '.json' ) ;
90- const cacheKey = 'imports:' + jsonFullPath . replace ( APP_PATH , '' ) ;
104+ const cacheKey = jsonFullPath . replace ( ` ${ APP_PATH } /` , '' ) ;
91105
92106 if ( ! jsonFullPath . startsWith ( APP_PATH ) ) {
93- reject ( new Error ( ERR_TOP_DIR ) ) ;
107+ callback ( new Error ( ERR_EXTERNAL_PATH ) , null ) ;
94108 return ;
95109 }
96110
97- if ( ! CachedData . hasOwnProperty ( cacheKey ) ) {
111+ if ( ! cachedData . hasOwnProperty ( cacheKey ) ) {
98112 try {
99113
100114 const jsonData = await Fs . promises . readFile ( jsonFullPath , 'utf8' ) ;
101115
102- CachedData [ cacheKey ] = JSON . parse ( jsonData ) ;
116+ cachedData [ cacheKey ] = JSON . parse ( jsonData ) ;
103117 action = 'Loaded' ;
104118
105119 } catch ( error ) {
106120
107- reject ( error ) ;
121+ callback ( error , null ) ;
108122 return ;
109123
110124 }
111125 }
112126
113127 report && reportAction ( ctx , jsonFullPath , jsonFilename , action ) ;
114128
115- Object . defineProperty ( storage , jsonFilename , {
116- value : CachedData [ cacheKey ] ,
129+ Object . defineProperty ( pocket , jsonFilename , {
130+ value : cachedData [ cacheKey ] ,
117131 enumerable : true
118132 } ) ;
119133
120134 options . idx = idx + 1 ;
121- loadImportsRecursively ( options ) ;
135+ loadImportsRecursively ( options , callback ) ;
122136
123- } else {
124- resolve ( storage ) ;
137+ } else if ( callback !== undefined ) {
138+ callback ( null , pocket ) ;
125139 }
126140}
127141
128142async function loadJsonData ( file ) {
129- const { report, pathHtml, pathData, dataEntry } = this ;
143+ const { report, pathHtml, pathData, dataEntry, cachedData } = this ;
130144
131- const pathJson = file . path
145+ const jsonFullPath = file . path
132146 . replace ( pathHtml , `${ pathData } /pages` )
133147 . slice ( 0 , - 3 ) + 'json' ;
134148
135- const cacheKey = 'data:' + pathJson . replace ( APP_PATH , '' ) ;
149+ const cacheKey = jsonFullPath . replace ( ` ${ APP_PATH } /` , '' ) ;
136150
137151 const filename = Path . basename ( file . path , '.pug' ) ;
138152 const pocket = { filename } ;
139153
140- if ( CachedData . hasOwnProperty ( pathJson ) ) {
141- report && reportAction ( this , pathJson , filename , 'Cached' ) ;
142- return CachedData [ cacheKey ] ;
154+ if ( cachedData . hasOwnProperty ( cacheKey ) ) {
155+ report && reportAction ( this , jsonFullPath , filename , 'Cached' ) ;
156+ return cachedData [ cacheKey ] ;
143157 }
144158
145159 let jsonData = '' ;
146160
147161 try {
148- jsonData = await Fs . promises . readFile ( pathJson , 'utf8' ) ;
162+ jsonData = await Fs . promises . readFile ( jsonFullPath , 'utf8' ) ;
149163 jsonData = JSON . parse ( jsonData ) ;
150164 } catch ( err ) {
151165 return pocket ;
152166 }
153167
154- report && reportAction ( this , pathJson , filename , 'Loaded' ) ;
168+ report && reportAction ( this , jsonFullPath , filename , 'Loaded' ) ;
155169
156170 if ( jsonData . hasOwnProperty ( 'imports' ) ) {
157171 const { data = { } , imports = [ ] } = jsonData ;
158172
159173 try {
160174
161- const importedData = await loadImportsAsync ( this , imports ) ;
175+ const importedData = await loadImportsAsync ( this , imports , cachedData ) ;
162176
163177 Object . defineProperty ( data , 'imports' , {
164178 value : importedData ,
@@ -170,7 +184,7 @@ async function loadJsonData(file) {
170184 const coloredErrorMesage = brush ( 'red' , err . message ) ;
171185 process . stderr . write ( coloredErrorMesage + BREAK_LINE ) ;
172186
173- return ;
187+ return pocket ;
174188
175189 }
176190
@@ -180,13 +194,13 @@ async function loadJsonData(file) {
180194 } ) ;
181195 }
182196
183- CachedData [ cacheKey ] = pocket ;
197+ cachedData [ cacheKey ] = pocket ;
184198
185199 return pocket ;
186200}
187201
188- const factory = ( options ) => {
189- if ( options === undefined ) {
202+ const factory = ( options , testMode = false ) => {
203+ if ( ! options ) {
190204 const packagePath = Path . join ( APP_PATH , 'package.json' ) ;
191205 const Package = require ( packagePath ) ;
192206
@@ -202,25 +216,57 @@ const factory = (options) => {
202216 : DEFAULT_SOURCE_PATH ;
203217
204218 const pathHtml = options . hasOwnProperty ( 'pathHtml' )
205- ? getAbsolutePath ( options . pathHtml )
206- : getAbsolutePath ( sourcePath , 'html' ) ;
219+ ? Path . join ( APP_PATH , options . pathHtml )
220+ : Path . join ( APP_PATH , sourcePath , 'html' ) ;
207221
208222 const pathData = options . hasOwnProperty ( 'pathData' )
209- ? getAbsolutePath ( options . pathData )
210- : getAbsolutePath ( sourcePath , 'data' ) ;
223+ ? Path . join ( APP_PATH , options . pathData )
224+ : Path . join ( APP_PATH , sourcePath , 'data' ) ;
211225
212226 if ( ! pathHtml . startsWith ( APP_PATH ) || ! pathData . startsWith ( APP_PATH ) ) {
213227 // Please put your source files into your project directory.
214- throw new Error ( ERR_TOP_DIR ) ;
228+ throw new Error ( ERR_EXTERNAL_PATH ) ;
215229 }
216230
217- return loadJsonData . bind ( {
231+ const context = {
232+ sourcePath,
218233 pathHtml,
219234 pathData,
220235 dataEntry,
221236 locales,
222237 report,
223- } ) ;
238+ cachedData : { }
239+ } ;
240+
241+ if ( testMode ) {
242+ return {
243+ context,
244+ loader : loadJsonData . bind ( context ) ,
245+ }
246+ }
247+
248+ return loadJsonData . bind ( context ) ;
249+ }
250+
251+ factory . forTest = ( ) => {
252+ return {
253+ // Package,
254+ // BrushColors,
255+
256+ constants : {
257+ APP_PATH ,
258+ DEFAULT_SOURCE_PATH ,
259+ BREAK_LINE ,
260+ ERR_EXTERNAL_PATH ,
261+ } ,
262+
263+ brush,
264+ reportAction,
265+ loadImportsAsync,
266+ loadImportsRecursively,
267+ loadJsonData,
268+ // factory,
269+ } ;
224270}
225271
226272module . exports = factory ;
0 commit comments