1
1
import { Syntax } from '../BlockParser' ;
2
2
import { ResolvedConfiguration } from '../configuration' ;
3
- import { Importer , FileIdentifier , ImportedFile } from './Importer' ;
3
+ import { Importer , FileIdentifier , ImportedFile , CompiledImportedFileCssContents , CompiledImportedFile } from './Importer' ;
4
+ import { REGEXP_COMMENT_HEADER , REGEXP_COMMENT_DEFINITION_REF , REGEXP_COMMENT_FOOTER } from '../PrecompiledDefinitions/compiled-comments' ;
4
5
5
6
/**
6
7
* The BaseImporter is an abstract class that Importer implementations may extend from.
@@ -17,7 +18,7 @@ export abstract class BaseImporter implements Importer {
17
18
/**
18
19
* Import the file with the given metadata and return a string and meta data for it.
19
20
*/
20
- abstract import ( identifier : FileIdentifier , config : ResolvedConfiguration ) : Promise < ImportedFile > ;
21
+ abstract import ( identifier : FileIdentifier , config : ResolvedConfiguration ) : Promise < ImportedFile | CompiledImportedFile > ;
21
22
/**
22
23
* The default name of the block used unless the block specifies one itself.
23
24
*/
@@ -36,4 +37,75 @@ export abstract class BaseImporter implements Importer {
36
37
* Returns the syntax the contents are written in.
37
38
*/
38
39
abstract syntax ( identifier : FileIdentifier , config : ResolvedConfiguration ) : Syntax ;
40
+
41
+ /**
42
+ * Determines if given file contents is a compiled CSS Blocks file.
43
+ * We determine this by looking for special auto-generated CSS Blocks
44
+ * comments in the file. We don't validate at this point that the data
45
+ * included in these comments is valid.
46
+ *
47
+ * @param contents - A string of the imported file contents to check.
48
+ * @returns True if this represents previously-compiled CSS, false otheerwise.
49
+ */
50
+ protected isCompiledBlockCSS ( contents : string ) : boolean {
51
+ return REGEXP_COMMENT_HEADER . test ( contents ) &&
52
+ REGEXP_COMMENT_DEFINITION_REF . test ( contents ) &&
53
+ REGEXP_COMMENT_FOOTER . test ( contents ) ;
54
+ }
55
+
56
+ /**
57
+ * Break apart a compiled CSS file that was previously generated from a block file
58
+ * into segments, based on the CSS Blocks comments that are present. If given a file
59
+ * that's missing expected auto-generated CSS Blocks comments, this will error.
60
+ * You should call isCompiledBlockCSS() first to determine if the file should be
61
+ * processed as a compiled CSS Block file.
62
+ *
63
+ * @param contents - A string of the imported file contents to check.
64
+ * @returns The segmented information from the compiled CSS file.
65
+ */
66
+ protected segmentizeCompiledBlockCSS ( contents : string ) : CompiledImportedFileCssContents {
67
+ // Use our regexps to find the start and end of the compiled content in the CSS file.
68
+ const headerRegexpResult = contents . match ( REGEXP_COMMENT_HEADER ) ;
69
+ const footerRegexpResult = contents . match ( REGEXP_COMMENT_FOOTER ) ;
70
+ if ( ! headerRegexpResult || ! footerRegexpResult ) {
71
+ throw new Error ( "Unable to parse compiled CSS file into segments. Expected comments are missing." ) ;
72
+ }
73
+
74
+ // Determine start/end indexes based on the regexp results above.
75
+ const [ headerFullMatch , blockIdFromComment ] = headerRegexpResult ;
76
+ const { index : headerStartIndex } = headerRegexpResult ;
77
+ if ( ! headerStartIndex ) {
78
+ throw new Error ( "Unable to determine start location of regexp result." ) ;
79
+ }
80
+ const headerEndIndex = headerStartIndex + headerFullMatch . length ;
81
+ const [ footerFullMatch ] = footerRegexpResult ;
82
+ const { index : footerStartIndex } = footerRegexpResult ;
83
+ if ( ! footerStartIndex ) {
84
+ throw new Error ( "Unable to determine start location of regexp result." ) ;
85
+ }
86
+ const footerEndIndex = footerStartIndex + footerFullMatch . length ;
87
+
88
+ // Break the file into segments.
89
+ const pre = contents . slice ( 0 , headerStartIndex ) ;
90
+ const post = contents . slice ( footerEndIndex + 1 ) ;
91
+ const fullBlockContents = contents . slice ( headerEndIndex + 1 , footerStartIndex ) ;
92
+
93
+ // Parse out the URL, or embedded data, for the block definition.
94
+ // The definition comment should be removed from the block's CSS contents.
95
+ const definitionRegexpResult = fullBlockContents . match ( REGEXP_COMMENT_DEFINITION_REF ) ;
96
+ if ( ! definitionRegexpResult ) {
97
+ throw new Error ( "Unable to find definition URL in compiled CSS. This comment must be declared between the header and footer CSS Blocks comments." ) ;
98
+ }
99
+ const [ definitionFullMatch , definitionUrl ] = definitionRegexpResult ;
100
+ const blockCssContents = fullBlockContents . replace ( definitionFullMatch , '' ) ;
101
+
102
+ return {
103
+ type : 'CompiledImportedFileCssContents' ,
104
+ pre,
105
+ blockIdFromComment,
106
+ blockCssContents,
107
+ definitionUrl,
108
+ post
109
+ } ;
110
+ }
39
111
}
0 commit comments