88use Drupal \Core \Theme \ThemeManagerInterface ;
99use Drupal \patternkit \Pattern ;
1010use Drupal \patternkit \PatternEditorConfig ;
11+ use Drupal \patternkit \PatternLibraryJSONParserTrait ;
1112use Drupal \patternkit \PatternLibraryParserBase ;
12- use Symfony \Component \Finder \Iterator \RecursiveDirectoryIterator ;
1313
1414/**
1515 * Parses a Twig pattern library collection into usable metadata.
1616 */
1717class TwigPatternLibraryParser extends PatternLibraryParserBase {
18-
19- /** @var \Drupal\Component\Serialization\SerializationInterface */
20- protected $ serializer ;
18+ use PatternLibraryJSONParserTrait;
2119
2220 /**
2321 * TwigPatternLibraryParser constructor.
2422 *
2523 * @param \Drupal\Component\Serialization\SerializationInterface $serializer
26- * Serialization service.
27- *
28- * {@inheritdoc}
24+ * Serializes and de-serializes data.
25+ * @param string $root
26+ * The application root path.
27+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
28+ * Allows modules to alter library parsing.
29+ * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
30+ * Allows themes to alter library parsing.
2931 */
30- public function __construct (SerializationInterface $ serializer , $ root , ModuleHandlerInterface $ module_handler , ThemeManagerInterface $ theme_manager ) {
32+ public function __construct (
33+ SerializationInterface $ serializer ,
34+ $ root ,
35+ ModuleHandlerInterface $ module_handler ,
36+ ThemeManagerInterface $ theme_manager ) {
37+
3138 $ this ->serializer = $ serializer ;
3239 parent ::__construct ($ root , $ module_handler , $ theme_manager );
3340 }
3441
35- /**
36- * Returns a new Patternkit Pattern.
37- *
38- * @param $name
39- * The name of the pattern.
40- * @param $schema
41- * The optional schema for the pattern.
42- *
43- * @return \Drupal\patternkit\Pattern
44- */
45- public function createPattern ($ name , $ schema ): Pattern {
46- return new Pattern ($ name , $ schema );
47- }
48-
4942 /**
5043 * Fetches all assets for a pattern.
5144 *
52- * @param Pattern $pattern
45+ * @param \Drupal\patternkit\ Pattern $pattern
5346 * The pattern to use for asset retrieval.
54- * @param PatternEditorConfig $config
47+ * @param \Drupal\patternkit\ PatternEditorConfig $config
5548 * The configuration object to use for provisioning the pattern.
5649 *
57- * @return Pattern
50+ * @return \Drupal\patternkit\ Pattern
5851 * The pattern parameter with updated asset references.
5952 */
6053 public function fetchPatternAssets (Pattern $ pattern ,
@@ -74,16 +67,12 @@ public function fetchPatternAssets(Pattern $pattern,
7467 * and defines the following elements:
7568 * - patterns: A list of pattern libraries and subtypes to include. Each
7669 * subtype is keyed by the subtype path.
77- * @code
70+ * @code
7871 * patterns:
79- * library:
80- * atoms:
81- * path/atoms: {}
82- * molecules:
83- * path/molecules: {}
84- * organisms:
85- * path/organisms: {}
86- * @endcode
72+ * path/atoms: {type: twig, category: atoms}
73+ * path/molecules: {type: twig, category: molecules}
74+ * path/organisms: {}
75+ * @endcode
8776 * - dependencies: A list of libraries this library depends on.
8877 * - version: The library version. The string "VERSION" can be used to mean
8978 * the current Drupal core version.
@@ -121,50 +110,26 @@ public function parseLibraryInfo($library, $path, array $library_data = []): arr
121110 if (!file_exists ($ path )) {
122111 throw new InvalidLibraryFileException ("Path $ path does not exist. " );
123112 }
124- $ rdit = new RecursiveDirectoryIterator ($ path , \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO );
125- $ filter = ['json ' , 'twig ' ];
126113 $ metadata = [];
127- $ components = [];
128-
129- /** @var \SplFileInfo $file */
130- foreach (new \RecursiveIteratorIterator ($ rdit ) as $ file ) {
131- // Skip directories and non-files.
132- if (!$ file ->isFile ()) {
114+ foreach (self ::discoverComponents ($ path , ['json ' , 'twig ' ]) as $ name => $ data ) {
115+ if (empty ($ data ['twig ' ]) || !file_exists ($ data ['twig ' ])) {
133116 continue ;
134117 }
135- $ file_path = $ file ->getPath ();
136-
137- // Skip tests folders.
138- if (strpos ($ file_path , '/tests ' ) !== FALSE ) {
139- continue ;
140- }
141-
142- // Get the file extension for the file.
143- $ file_ext = $ file ->getExtension ();
144- if (!in_array (strtolower ($ file_ext ), $ filter , TRUE )) {
145- continue ;
146- }
147-
148- // We use file_basename as a unique key, it is required that the
149- // JSON and twig file share this basename.
150- $ file_basename = $ file ->getBasename ('. ' . $ file_ext );
151-
152- // Build an array of all the filenames of interest, keyed by name.
153- $ components [$ file_basename ][$ file_ext ] = "$ file_path/ $ file_basename. $ file_ext " ;
154- }
155-
156- foreach ($ components as $ name => $ data ) {
157118 // If the component has a json file, create the pattern from it.
119+ $ category = $ library_data ['category ' ] ?? 'default ' ;
158120 if (!empty ($ data ['json ' ]) && $ file_contents = file_get_contents ($ data ['json ' ])) {
159121 $ pattern = $ this ->createPattern ($ name , (array ) $ this ->serializer ::decode ($ file_contents ) + $ library_data );
160- $ pattern ->name = $ name ;
122+ $ pattern_path = trim (substr ($ data ['json ' ], strlen ($ path ), -strlen ('.json ' )), '/ \\' );
123+ $ category_guess = $ library_data ['category ' ] ?? strstr ($ pattern_path , DIRECTORY_SEPARATOR , TRUE );
124+ $ pattern ->category = $ pattern ->category ?? $ category_guess ;
161125 }
162126 else {
163127 // Create the pattern from defaults.
128+ // @todo Have this cleverly infer defaults from the template.
164129 $ pattern = $ this ->createPattern ($ name ,
165130 [
166131 '$schema ' => 'http =>//json-schema.org/draft-04/schema# ' ,
167- 'category ' => ' atom ' ,
132+ 'category ' => $ category ,
168133 'title ' => $ name ,
169134 'type ' => 'object ' ,
170135 'format ' => 'grid ' ,
@@ -174,21 +139,15 @@ public function parseLibraryInfo($library, $path, array $library_data = []): arr
174139 ] + $ library_data
175140 );
176141 }
177-
178- if (!empty ($ data ['twig ' ])) {
179- $ twig_file = $ data ['twig ' ];
180- if (file_exists ($ twig_file )) {
181- $ pattern ->filename = trim (substr ($ twig_file , strlen ($ path )), '/ \\' );
182- $ pattern ->template = file_get_contents ($ twig_file );
183- // URL is redundant for the twig based components, so we use it to
184- // store namespace.
185- $ pattern ->url = $ library ;
186- // @todo add default of library version fallback to extension version.
187- $ pattern ->version = $ pattern ->version ?? 'VERSION ' ;
188- }
189- }
190-
191- $ metadata [$ name ] = $ pattern ;
142+ $ pattern ->filename = trim (substr ($ data ['twig ' ], strlen ($ path )), '/ \\' );
143+ $ pattern_path = substr ($ pattern ->filename , 0 , -strlen ('.twig ' ));
144+ $ pattern ->template = file_get_contents ($ data ['twig ' ]);
145+ // URL is redundant for the twig based components, so we use it to
146+ // store namespace.
147+ $ pattern ->url = $ library ;
148+ // @todo add default of library version fallback to extension version.
149+ $ pattern ->version = $ pattern ->version ?? 'VERSION ' ;
150+ $ metadata ["@ $ library/ $ pattern_path " ] = $ pattern ;
192151 }
193152
194153 foreach ($ metadata as $ pattern_type => $ pattern ) {
0 commit comments