1515use RecursiveDirectoryIterator ;
1616use RecursiveIteratorIterator ;
1717use RegexIterator ;
18+ use RocketTheme \Toolbox \Compat \Yaml \Yaml as CompatYaml ;
1819use RocketTheme \Toolbox \File \MarkdownFile ;
1920use RocketTheme \Toolbox \ResourceLocator \UniformResourceLocator ;
2021use Symfony \Component \Yaml \Yaml ;
@@ -30,44 +31,78 @@ class YamlLinter
3031 * @param callable|null $callback Optional callback for progress: function(string $file, bool $success, ?string $error)
3132 * @return array
3233 */
33- public static function lint (?string $ folder = null , ?callable $ callback = null )
34+ public static function lint (?string $ folder = null , ?callable $ callback = null , bool $ strict = false )
3435 {
3536 if (null !== $ folder ) {
3637 $ folder = $ folder ?: GRAV_ROOT ;
3738
38- return static ::recurseFolder ($ folder , '(md|yaml) ' , $ callback );
39+ return static ::recurseFolder ($ folder , '(md|yaml) ' , $ callback, $ strict );
3940 }
4041
4142 return array_merge (
42- static ::lintConfig ($ callback ),
43- static ::lintPages ($ callback ),
44- static ::lintBlueprints ($ callback )
43+ static ::lintConfig ($ callback , $ strict ),
44+ static ::lintPages ($ callback , $ strict ),
45+ static ::lintBlueprints ($ callback , $ strict ),
46+ static ::lintEnvironments ($ callback , $ strict )
4547 );
4648 }
4749
4850 /**
4951 * @param callable|null $callback Optional callback for progress: function(string $file, bool $success, ?string $error)
5052 * @return array
5153 */
52- public static function lintPages (?callable $ callback = null )
54+ public static function lintPages (?callable $ callback = null , bool $ strict = false )
5355 {
54- return static ::recurseFolder ('page:// ' , '(md|yaml) ' , $ callback );
56+ return static ::recurseFolder ('page:// ' , '(md|yaml) ' , $ callback, $ strict );
5557 }
5658
5759 /**
5860 * @param callable|null $callback Optional callback for progress: function(string $file, bool $success, ?string $error)
61+ * @param bool $strict Use the stricter Compat YAML parser (matches runtime behavior)
5962 * @return array
6063 */
61- public static function lintConfig (?callable $ callback = null )
64+ public static function lintConfig (?callable $ callback = null , bool $ strict = false )
6265 {
63- return static ::recurseFolder ('config:// ' , '(md|yaml) ' , $ callback );
66+ return static ::recurseFolder ('config:// ' , '(md|yaml) ' , $ callback, $ strict );
6467 }
6568
6669 /**
6770 * @param callable|null $callback Optional callback for progress: function(string $file, bool $success, ?string $error)
71+ * @param bool $strict Use the stricter Compat YAML parser (matches runtime behavior)
6872 * @return array
6973 */
70- public static function lintBlueprints (?callable $ callback = null )
74+ public static function lintEnvironments (?callable $ callback = null , bool $ strict = false )
75+ {
76+ $ lint_errors = [];
77+ $ user_path = GRAV_ROOT . '/ ' . GRAV_USER_PATH ;
78+
79+ // Scan Grav 1.6 style: user/<hostname>/config/
80+ foreach (glob ($ user_path . '/*/config ' , GLOB_ONLYDIR ) as $ envConfigDir ) {
81+ $ envName = basename (dirname ($ envConfigDir ));
82+ // Skip known non-environment directories
83+ if (in_array ($ envName , ['config ' , 'plugins ' , 'themes ' , 'pages ' , 'accounts ' , 'data ' , 'assets ' ])) {
84+ continue ;
85+ }
86+ $ lint_errors = array_merge ($ lint_errors , static ::recurseFolder ($ envConfigDir , '(md|yaml) ' , $ callback , $ strict ));
87+ }
88+
89+ // Scan Grav 1.7+ style: user/env/<hostname>/config/
90+ $ envPath = $ user_path . '/env ' ;
91+ if (is_dir ($ envPath )) {
92+ foreach (glob ($ envPath . '/*/config ' , GLOB_ONLYDIR ) as $ envConfigDir ) {
93+ $ lint_errors = array_merge ($ lint_errors , static ::recurseFolder ($ envConfigDir , '(md|yaml) ' , $ callback , $ strict ));
94+ }
95+ }
96+
97+ return $ lint_errors ;
98+ }
99+
100+ /**
101+ * @param callable|null $callback Optional callback for progress: function(string $file, bool $success, ?string $error)
102+ * @param bool $strict Use the stricter Compat YAML parser (matches runtime behavior)
103+ * @return array
104+ */
105+ public static function lintBlueprints (?callable $ callback = null , bool $ strict = false )
71106 {
72107 /** @var UniformResourceLocator $locator */
73108 $ locator = Grav::instance ()['locator ' ];
@@ -76,7 +111,7 @@ public static function lintBlueprints(?callable $callback = null)
76111 $ theme_path = 'themes:// ' . $ current_theme . '/blueprints ' ;
77112
78113 $ locator ->addPath ('blueprints ' , '' , [$ theme_path ]);
79- return static ::recurseFolder ('blueprints:// ' , '(md|yaml) ' , $ callback );
114+ return static ::recurseFolder ('blueprints:// ' , '(md|yaml) ' , $ callback, $ strict );
80115 }
81116
82117 /**
@@ -85,7 +120,7 @@ public static function lintBlueprints(?callable $callback = null)
85120 * @param callable|null $callback Optional callback for progress: function(string $file, bool $success, ?string $error)
86121 * @return array
87122 */
88- public static function recurseFolder ($ path , $ extensions = '(md|yaml) ' , ?callable $ callback = null )
123+ public static function recurseFolder ($ path , $ extensions = '(md|yaml) ' , ?callable $ callback = null , bool $ strict = false )
89124 {
90125 $ lint_errors = [];
91126
@@ -104,7 +139,12 @@ public static function recurseFolder($path, $extensions = '(md|yaml)', ?callable
104139 foreach ($ iterator as $ filepath => $ file ) {
105140 $ relativePath = str_replace (GRAV_ROOT , '' , $ filepath );
106141 try {
107- Yaml::parse (static ::extractYaml ($ filepath ));
142+ $ yaml = static ::extractYaml ($ filepath );
143+ if ($ strict ) {
144+ CompatYaml::parse ($ yaml );
145+ } else {
146+ Yaml::parse ($ yaml );
147+ }
108148 if ($ callback ) {
109149 $ callback ($ relativePath , true , null );
110150 }
0 commit comments