MediaWiki  master
ResourceLoaderFileModule.php
Go to the documentation of this file.
1 <?php
25 
41  protected $localBasePath = '';
42 
44  protected $remoteBasePath = '';
45 
47  protected $templates = [];
48 
56  protected $scripts = [];
57 
65  protected $languageScripts = [];
66 
74  protected $skinScripts = [];
75 
83  protected $debugScripts = [];
84 
92  protected $styles = [];
93 
101  protected $skinStyles = [];
102 
110  protected $packageFiles = null;
111 
116  private $expandedPackageFiles = [];
117 
123 
131  protected $dependencies = [];
132 
136  protected $skipFunction = null;
137 
145  protected $messages = [];
146 
148  protected $group;
149 
151  protected $debugRaw = true;
152 
154  protected $targets = [ 'desktop' ];
155 
157  protected $noflip = false;
158 
163  protected $hasGeneratedStyles = false;
164 
172  protected $localFileRefs = [];
173 
178  protected $missingLocalFileRefs = [];
179 
183  protected $vueComponentParser = null;
184 
196  public function __construct(
197  array $options = [],
198  $localBasePath = null,
199  $remoteBasePath = null
200  ) {
201  // Flag to decide whether to automagically add the mediawiki.template module
202  $hasTemplates = false;
203  // localBasePath and remoteBasePath both have unbelievably long fallback chains
204  // and need to be handled separately.
205  list( $this->localBasePath, $this->remoteBasePath ) =
207 
208  // Extract, validate and normalise remaining options
209  foreach ( $options as $member => $option ) {
210  switch ( $member ) {
211  // Lists of file paths
212  case 'scripts':
213  case 'debugScripts':
214  case 'styles':
215  case 'packageFiles':
216  $this->{$member} = is_array( $option ) ? $option : [ $option ];
217  break;
218  case 'templates':
219  $hasTemplates = true;
220  $this->{$member} = is_array( $option ) ? $option : [ $option ];
221  break;
222  // Collated lists of file paths
223  case 'languageScripts':
224  case 'skinScripts':
225  case 'skinStyles':
226  if ( !is_array( $option ) ) {
227  throw new InvalidArgumentException(
228  "Invalid collated file path list error. " .
229  "'$option' given, array expected."
230  );
231  }
232  foreach ( $option as $key => $value ) {
233  if ( !is_string( $key ) ) {
234  throw new InvalidArgumentException(
235  "Invalid collated file path list key error. " .
236  "'$key' given, string expected."
237  );
238  }
239  $this->{$member}[$key] = is_array( $value ) ? $value : [ $value ];
240  }
241  break;
242  case 'deprecated':
243  $this->deprecated = $option;
244  break;
245  // Lists of strings
246  case 'dependencies':
247  case 'messages':
248  case 'targets':
249  // Normalise
250  $option = array_values( array_unique( (array)$option ) );
251  sort( $option );
252 
253  $this->{$member} = $option;
254  break;
255  // Single strings
256  case 'group':
257  case 'skipFunction':
258  $this->{$member} = (string)$option;
259  break;
260  // Single booleans
261  case 'debugRaw':
262  case 'noflip':
263  $this->{$member} = (bool)$option;
264  break;
265  }
266  }
267  if ( isset( $options['scripts'] ) && isset( $options['packageFiles'] ) ) {
268  throw new InvalidArgumentException( "A module may not set both 'scripts' and 'packageFiles'" );
269  }
270  if ( isset( $options['packageFiles'] ) && isset( $options['skinScripts'] ) ) {
271  throw new InvalidArgumentException( "Options 'skinScripts' and 'packageFiles' cannot be used together." );
272  }
273  if ( $hasTemplates ) {
274  $this->dependencies[] = 'mediawiki.template';
275  // Ensure relevant template compiler module gets loaded
276  foreach ( $this->templates as $alias => $templatePath ) {
277  if ( is_int( $alias ) ) {
278  $alias = $this->getPath( $templatePath );
279  }
280  $suffix = explode( '.', $alias );
281  $suffix = end( $suffix );
282  $compilerModule = 'mediawiki.template.' . $suffix;
283  if ( $suffix !== 'html' && !in_array( $compilerModule, $this->dependencies ) ) {
284  $this->dependencies[] = $compilerModule;
285  }
286  }
287  }
288  }
289 
301  public static function extractBasePaths(
302  array $options = [],
303  $localBasePath = null,
304  $remoteBasePath = null
305  ) {
306  global $IP, $wgResourceBasePath;
307 
308  // The different ways these checks are done, and their ordering, look very silly,
309  // but were preserved for backwards-compatibility just in case. Tread lightly.
310 
311  if ( $localBasePath === null ) {
313  }
314  if ( $remoteBasePath === null ) {
316  }
317 
318  if ( isset( $options['remoteExtPath'] ) ) {
319  global $wgExtensionAssetsPath;
320  $remoteBasePath = $wgExtensionAssetsPath . '/' . $options['remoteExtPath'];
321  }
322 
323  if ( isset( $options['remoteSkinPath'] ) ) {
324  global $wgStylePath;
325  $remoteBasePath = $wgStylePath . '/' . $options['remoteSkinPath'];
326  }
327 
328  if ( array_key_exists( 'localBasePath', $options ) ) {
329  $localBasePath = (string)$options['localBasePath'];
330  }
331 
332  if ( array_key_exists( 'remoteBasePath', $options ) ) {
333  $remoteBasePath = (string)$options['remoteBasePath'];
334  }
335 
336  if ( $remoteBasePath === '' ) {
337  // If MediaWiki is installed at the document root (not recommended),
338  // then wgScriptPath is set to the empty string by the installer to
339  // ensure safe concatenating of file paths (avoid "/" + "/foo" being "//foo").
340  // However, this also means the path itself can be an invalid URI path,
341  // as those must start with a slash. Within ResourceLoader, we will not
342  // do such primitive/unsafe slash concatenation and use URI resolution
343  // instead, so beyond this point, to avoid fatal errors in CSSMin::resolveUrl(),
344  // do a best-effort support for docroot installs by casting this to a slash.
345  $remoteBasePath = '/';
346  }
347 
348  return [ $localBasePath, $remoteBasePath ];
349  }
350 
357  public function getScript( ResourceLoaderContext $context ) {
358  $deprecationScript = $this->getDeprecationInformation( $context );
359  if ( $this->packageFiles !== null ) {
360  $packageFiles = $this->getPackageFiles( $context );
361  foreach ( $packageFiles['files'] as &$file ) {
362  if ( $file['type'] === 'script+style' ) {
363  $file['content'] = $file['content']['script'];
364  $file['type'] = 'script';
365  }
366  }
367  if ( $deprecationScript ) {
368  $mainFile =& $packageFiles['files'][$packageFiles['main']];
369  $mainFile['content'] = $deprecationScript . $mainFile['content'];
370  }
371  return $packageFiles;
372  }
373 
374  $files = $this->getScriptFiles( $context );
375  return $deprecationScript . $this->readScriptFiles( $files );
376  }
377 
382  public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
383  $urls = [];
384  foreach ( $this->getScriptFiles( $context ) as $file ) {
386  $this->getConfig(),
387  $this->getRemotePath( $file )
388  );
389  }
390  return $urls;
391  }
392 
396  public function supportsURLLoading() {
397  // If package files are involved, don't support URL loading, because that breaks
398  // scoped require() functions
399  return $this->debugRaw && !$this->packageFiles;
400  }
401 
408  public function getStyles( ResourceLoaderContext $context ) {
409  $styles = $this->readStyleFiles(
410  $this->getStyleFiles( $context ),
411  $context
412  );
413 
414  if ( $this->packageFiles !== null ) {
415  $packageFiles = $this->getPackageFiles( $context );
416  foreach ( $packageFiles['files'] as $fileName => $file ) {
417  if ( $file['type'] === 'script+style' ) {
418  $style = $this->processStyle(
419  $file['content']['style'],
420  $file['content']['styleLang'],
421  $fileName,
422  $context
423  );
424  $styles['all'] = ( $styles['all'] ?? '' ) . "\n" . $style;
425  }
426  }
427  }
428 
429  // Track indirect file dependencies so that ResourceLoaderStartUpModule can check for
430  // on-disk file changes to any of this files without having to recompute the file list
431  $this->saveFileDependencies( $context, $this->localFileRefs );
432 
433  return $styles;
434  }
435 
440  public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
441  if ( $this->hasGeneratedStyles ) {
442  // Do the default behaviour of returning a url back to load.php
443  // but with only=styles.
444  return parent::getStyleURLsForDebug( $context );
445  }
446  // Our module consists entirely of real css files,
447  // in debug mode we can load those directly.
448  $urls = [];
449  foreach ( $this->getStyleFiles( $context ) as $mediaType => $list ) {
450  $urls[$mediaType] = [];
451  foreach ( $list as $file ) {
452  $urls[$mediaType][] = OutputPage::transformResourcePath(
453  $this->getConfig(),
454  $this->getRemotePath( $file )
455  );
456  }
457  }
458  return $urls;
459  }
460 
466  public function getMessages() {
467  return $this->messages;
468  }
469 
475  public function getGroup() {
476  return $this->group;
477  }
478 
484  public function getDependencies( ResourceLoaderContext $context = null ) {
485  return $this->dependencies;
486  }
487 
496  private function getFileContents( $localPath, $type ) {
497  if ( !is_file( $localPath ) ) {
498  throw new RuntimeException(
499  __METHOD__ . ": $type file not found, or is not a file: \"$localPath\""
500  );
501  }
502  return $this->stripBom( file_get_contents( $localPath ) );
503  }
504 
509  public function getSkipFunction() {
510  if ( !$this->skipFunction ) {
511  return null;
512  }
513  $localPath = $this->getLocalPath( $this->skipFunction );
514  return $this->getFileContents( $localPath, 'skip function' );
515  }
516 
525  public function enableModuleContentVersion() {
526  return false;
527  }
528 
535  private function getFileHashes( ResourceLoaderContext $context ) {
536  $files = [];
537 
538  // Flatten style files into $files
539  $styles = self::collateFilePathListByOption( $this->styles, 'media', 'all' );
540  foreach ( $styles as $styleFiles ) {
541  $files = array_merge( $files, $styleFiles );
542  }
543 
545  self::tryForKey( $this->skinStyles, $context->getSkin(), 'default' ),
546  'media',
547  'all'
548  );
549  foreach ( $skinFiles as $styleFiles ) {
550  $files = array_merge( $files, $styleFiles );
551  }
552 
553  // Extract file paths for package files
554  // Optimisation: Use foreach() and isset() instead of array_map/array_filter.
555  // This is a hot code path, called by StartupModule for thousands of modules.
556  $expandedPackageFiles = $this->expandPackageFiles( $context );
557  $packageFiles = [];
558  if ( $expandedPackageFiles ) {
559  foreach ( $expandedPackageFiles['files'] as $fileInfo ) {
560  if ( isset( $fileInfo['filePath'] ) ) {
561  $packageFiles[] = $fileInfo['filePath'];
562  }
563  }
564  }
565 
566  // Merge all the file paths we were able discover directly from the module definition.
567  // This is the master list of direct-dependent files for this module.
568  $files = array_merge(
569  $files,
571  $this->scripts,
572  $this->templates,
573  $context->getDebug() ? $this->debugScripts : [],
574  $this->getLanguageScripts( $context->getLanguage() ),
575  self::tryForKey( $this->skinScripts, $context->getSkin(), 'default' )
576  );
577  if ( $this->skipFunction ) {
578  $files[] = $this->skipFunction;
579  }
580 
581  // Expand these local paths into absolute file paths
582  $files = array_map( [ $this, 'getLocalPath' ], $files );
583 
584  // Add any lazily discovered file dependencies from previous module builds.
585  // These are added last because they are already absolute file paths.
586  $files = array_merge( $files, $this->getFileDependencies( $context ) );
587 
588  // Filter out any duplicates. Typically introduced by getFileDependencies() which
589  // may lazily re-discover a master file.
590  $files = array_unique( $files );
591 
592  // Don't return array keys or any other form of file path here, only the hashes.
593  // Including file paths would needlessly cause global cache invalidation when files
594  // move on disk or if e.g. the MediaWiki directory name changes.
595  // Anything where order is significant is already detected by the definition summary.
597  }
598 
605  public function getDefinitionSummary( ResourceLoaderContext $context ) {
606  $summary = parent::getDefinitionSummary( $context );
607 
608  $options = [];
609  foreach ( [
610  // The following properties are omitted because they don't affect the module reponse:
611  // - localBasePath (Per T104950; Changes when absolute directory name changes. If
612  // this affects 'scripts' and other file paths, getFileHashes accounts for that.)
613  // - remoteBasePath (Per T104950)
614  // - dependencies (provided via startup module)
615  // - targets
616  // - group (provided via startup module)
617  'scripts',
618  'debugScripts',
619  'styles',
620  'languageScripts',
621  'skinScripts',
622  'skinStyles',
623  'messages',
624  'templates',
625  'skipFunction',
626  'debugRaw',
627  ] as $member ) {
628  $options[$member] = $this->{$member};
629  }
630 
631  $packageFiles = $this->expandPackageFiles( $context );
632  if ( $packageFiles ) {
633  // Extract the minimum needed:
634  // - The 'main' pointer (included as-is).
635  // - The 'files' array, simplified to only which files exist (the keys of
636  // this array), and something that represents their non-file content.
637  // For packaged files that reflect files directly from disk, the
638  // 'getFileHashes' method tracks their content already.
639  // It is important that the keys of the $packageFiles['files'] array
640  // are preserved, as they do affect the module output.
641  $packageFiles['files'] = array_map( function ( $fileInfo ) {
642  return $fileInfo['definitionSummary'] ?? ( $fileInfo['content'] ?? null );
643  }, $packageFiles['files'] );
644  }
645 
646  $summary[] = [
647  'options' => $options,
648  'packageFiles' => $packageFiles,
649  'fileHashes' => $this->getFileHashes( $context ),
650  'messageBlob' => $this->getMessageBlob( $context ),
651  ];
652 
653  $lessVars = $this->getLessVars( $context );
654  if ( $lessVars ) {
655  $summary[] = [ 'lessVars' => $lessVars ];
656  }
657 
658  return $summary;
659  }
660 
664  protected function getVueComponentParser() {
665  if ( $this->vueComponentParser === null ) {
666  $this->vueComponentParser = new VueComponentParser;
667  }
669  }
670 
675  protected function getPath( $path ) {
676  if ( $path instanceof ResourceLoaderFilePath ) {
677  return $path->getPath();
678  }
679 
680  return $path;
681  }
682 
687  protected function getLocalPath( $path ) {
688  if ( $path instanceof ResourceLoaderFilePath ) {
689  return $path->getLocalPath();
690  }
691 
692  return "{$this->localBasePath}/$path";
693  }
694 
699  protected function getRemotePath( $path ) {
700  if ( $path instanceof ResourceLoaderFilePath ) {
701  return $path->getRemotePath();
702  }
703 
704  return "{$this->remoteBasePath}/$path";
705  }
706 
714  public function getStyleSheetLang( $path ) {
715  return preg_match( '/\.less$/i', $path ) ? 'less' : 'css';
716  }
717 
723  public static function getPackageFileType( $path ) {
724  if ( preg_match( '/\.json$/i', $path ) ) {
725  return 'data';
726  }
727  if ( preg_match( '/\.vue$/i', $path ) ) {
728  return 'script-vue';
729  }
730  return 'script';
731  }
732 
742  protected static function collateFilePathListByOption( array $list, $option, $default ) {
743  $collatedFiles = [];
744  foreach ( $list as $key => $value ) {
745  if ( is_int( $key ) ) {
746  // File name as the value
747  if ( !isset( $collatedFiles[$default] ) ) {
748  $collatedFiles[$default] = [];
749  }
750  $collatedFiles[$default][] = $value;
751  } elseif ( is_array( $value ) ) {
752  // File name as the key, options array as the value
753  $optionValue = $value[$option] ?? $default;
754  if ( !isset( $collatedFiles[$optionValue] ) ) {
755  $collatedFiles[$optionValue] = [];
756  }
757  $collatedFiles[$optionValue][] = $key;
758  }
759  }
760  return $collatedFiles;
761  }
762 
772  protected static function tryForKey( array $list, $key, $fallback = null ) {
773  if ( isset( $list[$key] ) && is_array( $list[$key] ) ) {
774  return $list[$key];
775  } elseif ( is_string( $fallback )
776  && isset( $list[$fallback] )
777  && is_array( $list[$fallback] )
778  ) {
779  return $list[$fallback];
780  }
781  return [];
782  }
783 
790  private function getScriptFiles( ResourceLoaderContext $context ) {
791  $files = array_merge(
792  $this->scripts,
793  $this->getLanguageScripts( $context->getLanguage() ),
794  self::tryForKey( $this->skinScripts, $context->getSkin(), 'default' )
795  );
796  if ( $context->getDebug() ) {
797  $files = array_merge( $files, $this->debugScripts );
798  }
799 
800  return array_unique( $files, SORT_REGULAR );
801  }
802 
810  private function getLanguageScripts( $lang ) {
811  $scripts = self::tryForKey( $this->languageScripts, $lang );
812  if ( $scripts ) {
813  return $scripts;
814  }
815  $fallbacks = MediaWikiServices::getInstance()->getLanguageFallback()
816  ->getAll( $lang, LanguageFallback::MESSAGES );
817  foreach ( $fallbacks as $lang ) {
818  $scripts = self::tryForKey( $this->languageScripts, $lang );
819  if ( $scripts ) {
820  return $scripts;
821  }
822  }
823 
824  return [];
825  }
826 
834  public function getStyleFiles( ResourceLoaderContext $context ) {
835  return array_merge_recursive(
836  self::collateFilePathListByOption( $this->styles, 'media', 'all' ),
837  self::collateFilePathListByOption(
838  self::tryForKey( $this->skinStyles, $context->getSkin(), 'default' ),
839  'media',
840  'all'
841  )
842  );
843  }
844 
852  protected function getSkinStyleFiles( $skinName ) {
854  self::tryForKey( $this->skinStyles, $skinName ),
855  'media',
856  'all'
857  );
858  }
859 
866  protected function getAllSkinStyleFiles() {
867  $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
868  $styleFiles = [];
869 
870  $internalSkinNames = array_keys( $skinFactory->getSkinNames() );
871  $internalSkinNames[] = 'default';
872 
873  foreach ( $internalSkinNames as $internalSkinName ) {
874  $styleFiles = array_merge_recursive(
875  $styleFiles,
876  $this->getSkinStyleFiles( $internalSkinName )
877  );
878  }
879 
880  return $styleFiles;
881  }
882 
888  public function getAllStyleFiles() {
889  $collatedStyleFiles = array_merge_recursive(
890  self::collateFilePathListByOption( $this->styles, 'media', 'all' ),
891  $this->getAllSkinStyleFiles()
892  );
893 
894  $result = [];
895 
896  foreach ( $collatedStyleFiles as $media => $styleFiles ) {
897  foreach ( $styleFiles as $styleFile ) {
898  $result[] = $this->getLocalPath( $styleFile );
899  }
900  }
901 
902  return $result;
903  }
904 
912  private function readScriptFiles( array $scripts ) {
913  if ( empty( $scripts ) ) {
914  return '';
915  }
916  $js = '';
917  foreach ( array_unique( $scripts, SORT_REGULAR ) as $fileName ) {
918  $localPath = $this->getLocalPath( $fileName );
919  $contents = $this->getFileContents( $localPath, 'script' );
920  $js .= $contents . "\n";
921  }
922  return $js;
923  }
924 
935  public function readStyleFiles( array $styles, ResourceLoaderContext $context ) {
936  if ( !$styles ) {
937  return [];
938  }
939  foreach ( $styles as $media => $files ) {
940  $uniqueFiles = array_unique( $files, SORT_REGULAR );
941  $styleFiles = [];
942  foreach ( $uniqueFiles as $file ) {
943  $styleFiles[] = $this->readStyleFile( $file, $context );
944  }
945  $styles[$media] = implode( "\n", $styleFiles );
946  }
947  return $styles;
948  }
949 
961  protected function readStyleFile( $path, ResourceLoaderContext $context ) {
962  $localPath = $this->getLocalPath( $path );
963  $style = $this->getFileContents( $localPath, 'style' );
964  $styleLang = $this->getStyleSheetLang( $localPath );
965 
966  return $this->processStyle( $style, $styleLang, $path, $context );
967  }
968 
985  protected function processStyle( $style, $styleLang, $path, ResourceLoaderContext $context ) {
986  $localPath = $this->getLocalPath( $path );
987  $remotePath = $this->getRemotePath( $path );
988 
989  if ( $styleLang === 'less' ) {
990  $style = $this->compileLessString( $style, $localPath, $context );
991  $this->hasGeneratedStyles = true;
992  }
993 
994  if ( $this->getFlip( $context ) ) {
995  $style = CSSJanus::transform(
996  $style,
997  /* $swapLtrRtlInURL = */ true,
998  /* $swapLeftRightInURL = */ false
999  );
1000  }
1001 
1002  $localDir = dirname( $localPath );
1003  $remoteDir = dirname( $remotePath );
1004  // Get and register local file references
1005  $localFileRefs = CSSMin::getLocalFileReferences( $style, $localDir );
1006  foreach ( $localFileRefs as $file ) {
1007  if ( file_exists( $file ) ) {
1008  $this->localFileRefs[] = $file;
1009  } else {
1010  $this->missingLocalFileRefs[] = $file;
1011  }
1012  }
1013  // Don't cache this call. remap() ensures data URIs embeds are up to date,
1014  // and urls contain correct content hashes in their query string. (T128668)
1015  return CSSMin::remap( $style, $localDir, $remoteDir, true );
1016  }
1017 
1023  public function getFlip( ResourceLoaderContext $context ) {
1024  return $context->getDirection() === 'rtl' && !$this->noflip;
1025  }
1026 
1032  public function getTargets() {
1033  return $this->targets;
1034  }
1035 
1042  public function getType() {
1043  $canBeStylesOnly = !(
1044  // All options except 'styles', 'skinStyles' and 'debugRaw'
1045  $this->scripts
1046  || $this->debugScripts
1047  || $this->templates
1048  || $this->languageScripts
1049  || $this->skinScripts
1050  || $this->dependencies
1051  || $this->messages
1052  || $this->skipFunction
1054  );
1055  return $canBeStylesOnly ? self::LOAD_STYLES : self::LOAD_GENERAL;
1056  }
1057 
1065  protected function compileLessFile( $fileName, ResourceLoaderContext $context ) {
1066  wfDeprecated( __METHOD__, '1.35' );
1067 
1068  $style = $this->getFileContents( $fileName, 'LESS' );
1069  return $this->compileLessString( $style, $fileName, $context );
1070  }
1071 
1084  protected function compileLessString( $style, $stylePath, ResourceLoaderContext $context ) {
1085  static $cache;
1086  // @TODO: dependency injection
1087  if ( !$cache ) {
1089  }
1090 
1091  $skinName = $context->getSkin();
1092  $skinImportPaths = ExtensionRegistry::getInstance()->getAttribute( 'SkinLessImportPaths' );
1093  $importDirs = [];
1094  if ( isset( $skinImportPaths[ $skinName ] ) ) {
1095  $importDirs[] = $skinImportPaths[ $skinName ];
1096  }
1097 
1098  $vars = $this->getLessVars( $context );
1099  // Construct a cache key from a hash of the LESS source, and a hash digest
1100  // of the LESS variables used for compilation.
1101  ksort( $vars );
1102  $compilerParams = [
1103  'vars' => $vars,
1104  'importDirs' => $importDirs,
1105  ];
1106  $key = $cache->makeGlobalKey(
1107  'resourceloader-less',
1108  'v1',
1109  hash( 'md4', $style ),
1110  hash( 'md4', serialize( $compilerParams ) )
1111  );
1112 
1113  // If we got a cached value, we have to validate it by getting a checksum of all the
1114  // files that were loaded by the parser and ensuring it matches the cached entry's.
1115  $data = $cache->get( $key );
1116  if (
1117  !$data ||
1118  $data['hash'] !== FileContentsHasher::getFileContentsHash( $data['files'] )
1119  ) {
1120  $compiler = $context->getResourceLoader()->getLessCompiler( $vars, $importDirs );
1121 
1122  $css = $compiler->parse( $style, $stylePath )->getCss();
1123  // T253055: store the implicit dependency paths in a form relative to any install
1124  // path so that multiple version of the application can share the cache for identical
1125  // less stylesheets. This also avoids churn during application updates.
1126  $files = $compiler->AllParsedFiles();
1127  $data = [
1128  'css' => $css,
1129  'files' => ResourceLoaderModule::getRelativePaths( $files ),
1130  'hash' => FileContentsHasher::getFileContentsHash( $files )
1131  ];
1132  $cache->set( $key, $data, $cache::TTL_DAY );
1133  }
1134 
1135  foreach ( ResourceLoaderModule::expandRelativePaths( $data['files'] ) as $path ) {
1136  $this->localFileRefs[] = $path;
1137  }
1138 
1139  return $data['css'];
1140  }
1141 
1147  public function getTemplates() {
1148  $templates = [];
1149 
1150  foreach ( $this->templates as $alias => $templatePath ) {
1151  // Alias is optional
1152  if ( is_int( $alias ) ) {
1153  $alias = $this->getPath( $templatePath );
1154  }
1155  $localPath = $this->getLocalPath( $templatePath );
1156  $content = $this->getFileContents( $localPath, 'template' );
1157 
1158  $templates[$alias] = $this->stripBom( $content );
1159  }
1160  return $templates;
1161  }
1162 
1182  private function expandPackageFiles( ResourceLoaderContext $context ) {
1183  $hash = $context->getHash();
1184  if ( isset( $this->expandedPackageFiles[$hash] ) ) {
1185  return $this->expandedPackageFiles[$hash];
1186  }
1187  if ( $this->packageFiles === null ) {
1188  return null;
1189  }
1190  $expandedFiles = [];
1191  $mainFile = null;
1192 
1193  foreach ( $this->packageFiles as $key => $fileInfo ) {
1194  if ( is_string( $fileInfo ) ) {
1195  $fileInfo = [ 'name' => $fileInfo, 'file' => $fileInfo ];
1196  }
1197  if ( !isset( $fileInfo['name'] ) ) {
1198  $msg = "Missing 'name' key in package file info for module '{$this->getName()}'," .
1199  " offset '{$key}'.";
1200  $this->getLogger()->error( $msg );
1201  throw new LogicException( $msg );
1202  }
1203  $fileName = $fileInfo['name'];
1204 
1205  // Infer type from alias if needed
1206  $type = $fileInfo['type'] ?? self::getPackageFileType( $fileName );
1207  $expanded = [ 'type' => $type ];
1208  if ( !empty( $fileInfo['main'] ) ) {
1209  $mainFile = $fileName;
1210  if ( $type !== 'script' && $type !== 'script-vue' ) {
1211  $msg = "Main file in package must be of type 'script', module " .
1212  "'{$this->getName()}', main file '{$mainFile}' is '{$type}'.";
1213  $this->getLogger()->error( $msg );
1214  throw new LogicException( $msg );
1215  }
1216  }
1217 
1218  // Perform expansions (except 'file' and 'callback'), creating one of these keys:
1219  // - 'content': literal value.
1220  // - 'filePath': content to be read from a file.
1221  // - 'callback': content computed by a callable.
1222  if ( isset( $fileInfo['content'] ) ) {
1223  $expanded['content'] = $fileInfo['content'];
1224  } elseif ( isset( $fileInfo['file'] ) ) {
1225  $expanded['filePath'] = $fileInfo['file'];
1226  } elseif ( isset( $fileInfo['callback'] ) ) {
1227  // If no extra parameter for the callback is given, use null.
1228  $expanded['callbackParam'] = $fileInfo['callbackParam'] ?? null;
1229 
1230  if ( !is_callable( $fileInfo['callback'] ) ) {
1231  $msg = "Invalid 'callback' for module '{$this->getName()}', file '{$fileName}'.";
1232  $this->getLogger()->error( $msg );
1233  throw new LogicException( $msg );
1234  }
1235  if ( isset( $fileInfo['versionCallback'] ) ) {
1236  if ( !is_callable( $fileInfo['versionCallback'] ) ) {
1237  throw new LogicException( "Invalid 'versionCallback' for "
1238  . "module '{$this->getName()}', file '{$fileName}'."
1239  );
1240  }
1241 
1242  // Execute the versionCallback with the same arguments that
1243  // would be given to the callback
1244  $callbackResult = ( $fileInfo['versionCallback'] )(
1245  $context,
1246  $this->getConfig(),
1247  $expanded['callbackParam']
1248  );
1249  if ( $callbackResult instanceof ResourceLoaderFilePath ) {
1250  $expanded['filePath'] = $callbackResult->getPath();
1251  } else {
1252  $expanded['definitionSummary'] = $callbackResult;
1253  }
1254  // Don't invoke 'callback' here as it may be expensive (T223260).
1255  $expanded['callback'] = $fileInfo['callback'];
1256  } else {
1257  // Else go ahead invoke callback with its arguments.
1258  $callbackResult = ( $fileInfo['callback'] )(
1259  $context,
1260  $this->getConfig(),
1261  $expanded['callbackParam']
1262  );
1263  if ( $callbackResult instanceof ResourceLoaderFilePath ) {
1264  $expanded['filePath'] = $callbackResult->getPath();
1265  } else {
1266  $expanded['content'] = $callbackResult;
1267  }
1268  }
1269  } elseif ( isset( $fileInfo['config'] ) ) {
1270  if ( $type !== 'data' ) {
1271  $msg = "Key 'config' only valid for data files. "
1272  . " Module '{$this->getName()}', file '{$fileName}' is '{$type}'.";
1273  $this->getLogger()->error( $msg );
1274  throw new LogicException( $msg );
1275  }
1276  $expandedConfig = [];
1277  foreach ( $fileInfo['config'] as $key => $var ) {
1278  $expandedConfig[ is_numeric( $key ) ? $var : $key ] = $this->getConfig()->get( $var );
1279  }
1280  $expanded['content'] = $expandedConfig;
1281  } elseif ( !empty( $fileInfo['main'] ) ) {
1282  // [ 'name' => 'foo.js', 'main' => true ] is shorthand
1283  $expanded['filePath'] = $fileName;
1284  } else {
1285  $msg = "Incomplete definition for module '{$this->getName()}', file '{$fileName}'. "
1286  . "One of 'file', 'content', 'callback', or 'config' must be set.";
1287  $this->getLogger()->error( $msg );
1288  throw new LogicException( $msg );
1289  }
1290 
1291  $expandedFiles[$fileName] = $expanded;
1292  }
1293 
1294  if ( $expandedFiles && $mainFile === null ) {
1295  // The first package file that is a script is the main file
1296  foreach ( $expandedFiles as $path => $file ) {
1297  if ( $file['type'] === 'script' || $file['type'] === 'script-vue' ) {
1298  $mainFile = $path;
1299  break;
1300  }
1301  }
1302  }
1303 
1304  $result = [
1305  'main' => $mainFile,
1306  'files' => $expandedFiles
1307  ];
1308 
1309  $this->expandedPackageFiles[$hash] = $result;
1310  return $result;
1311  }
1312 
1319  public function getPackageFiles( ResourceLoaderContext $context ) {
1320  if ( $this->packageFiles === null ) {
1321  return null;
1322  }
1323  $hash = $context->getHash();
1324  if ( isset( $this->fullyExpandedPackageFiles[ $hash ] ) ) {
1325  return $this->fullyExpandedPackageFiles[ $hash ];
1326  }
1327  $expandedPackageFiles = $this->expandPackageFiles( $context );
1328 
1329  // Expand file contents
1330  foreach ( $expandedPackageFiles['files'] as $fileName => &$fileInfo ) {
1331  // Turn any 'filePath' or 'callback' key into actual 'content',
1332  // and remove the key after that. The callback could return a
1333  // ResourceLoaderFilePath object; if that happens, fall through
1334  // to the 'filePath' handling.
1335  if ( isset( $fileInfo['callback'] ) ) {
1336  $callbackResult = ( $fileInfo['callback'] )(
1337  $context,
1338  $this->getConfig(),
1339  $fileInfo['callbackParam']
1340  );
1341  if ( $callbackResult instanceof ResourceLoaderFilePath ) {
1342  // Fall through to the filePath handling code below
1343  $fileInfo['filePath'] = $callbackResult->getPath();
1344  } else {
1345  $fileInfo['content'] = $callbackResult;
1346  }
1347  unset( $fileInfo['callback'] );
1348  }
1349  // Only interpret 'filePath' if 'content' hasn't been set already.
1350  // This can happen if 'versionCallback' provided 'filePath',
1351  // while 'callback' provides 'content'. In that case both are set
1352  // at this point. The 'filePath' from 'versionCallback' in that case is
1353  // only to inform getDefinitionSummary().
1354  if ( !isset( $fileInfo['content'] ) && isset( $fileInfo['filePath'] ) ) {
1355  $localPath = $this->getLocalPath( $fileInfo['filePath'] );
1356  $content = $this->getFileContents( $localPath, 'package' );
1357  if ( $fileInfo['type'] === 'data' ) {
1358  $content = json_decode( $content );
1359  }
1360  $fileInfo['content'] = $content;
1361  unset( $fileInfo['filePath'] );
1362  }
1363  if ( $fileInfo['type'] === 'script-vue' ) {
1364  try {
1365  $parsedComponent = $this->getVueComponentParser()->parse(
1366  $fileInfo['content'],
1367  [ 'minifyTemplate' => !$context->getDebug() ]
1368  );
1369  } catch ( Exception $e ) {
1370  $msg = "Error parsing file '$fileName' in module '{$this->getName()}': " .
1371  $e->getMessage();
1372  $this->getLogger()->error( $msg );
1373  throw new RuntimeException( $msg );
1374  }
1375  $encodedTemplate = json_encode( $parsedComponent['template'] );
1376  if ( $context->getDebug() ) {
1377  // Replace \n (backslash-n) with space + backslash-newline in debug mode
1378  // We only replace \n if not preceded by a backslash, to avoid breaking '\\n'
1379  $encodedTemplate = preg_replace( '/(?<!\\\\)\\\\n/', " \\\n", $encodedTemplate );
1380  // Expand \t to real tabs in debug mode
1381  $encodedTemplate = strtr( $encodedTemplate, [ "\\t" => "\t" ] );
1382  }
1383  $fileInfo['content'] = [
1384  'script' => $parsedComponent['script'] .
1385  ";\nmodule.exports.template = $encodedTemplate;",
1386  'style' => $parsedComponent['style'] ?? '',
1387  'styleLang' => $parsedComponent['styleLang'] ?? 'css'
1388  ];
1389  $fileInfo['type'] = 'script+style';
1390  }
1391 
1392  // Not needed for client response, exists for use by getDefinitionSummary().
1393  unset( $fileInfo['definitionSummary'] );
1394  // Not needed for client response, used by callbacks only.
1395  unset( $fileInfo['callbackParam'] );
1396  }
1397 
1398  $this->fullyExpandedPackageFiles[ $hash ] = $expandedPackageFiles;
1399  return $expandedPackageFiles;
1400  }
1401 
1412  protected function stripBom( $input ) {
1413  if ( substr_compare( "\xef\xbb\xbf", $input, 0, 3 ) === 0 ) {
1414  return substr( $input, 3 );
1415  }
1416  return $input;
1417  }
1418 }
ResourceLoaderFileModule\getSkipFunction
getSkipFunction()
Definition: ResourceLoaderFileModule.php:509
ResourceLoaderContext
Context object that contains information about the state of a specific ResourceLoader web request.
Definition: ResourceLoaderContext.php:33
ResourceLoaderFileModule\$styles
array $styles
List of paths to CSS files to always include.
Definition: ResourceLoaderFileModule.php:92
ResourceLoaderFileModule\$skinScripts
array $skinScripts
List of JavaScript files to include when using a specific skin.
Definition: ResourceLoaderFileModule.php:74
ResourceLoaderContext\getDirection
getDirection()
Definition: ResourceLoaderContext.php:174
ResourceLoaderFileModule\$debugScripts
array $debugScripts
List of paths to JavaScript files to include in debug mode.
Definition: ResourceLoaderFileModule.php:83
CACHE_ANYTHING
const CACHE_ANYTHING
Definition: Defines.php:84
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:166
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
ResourceLoaderContext\getResourceLoader
getResourceLoader()
Definition: ResourceLoaderContext.php:123
ResourceLoaderFileModule\$templates
array $templates
Saves a list of the templates named by the modules.
Definition: ResourceLoaderFileModule.php:47
CSSMin\remap
static remap( $source, $local, $remote, $embedData=true)
Remaps CSS URL paths and automatically embeds data URIs for CSS rules or url() values preceded by an ...
Definition: CSSMin.php:238
ResourceLoaderModule\$contents
array $contents
Map of (context hash => cached module content)
Definition: ResourceLoaderModule.php:66
ResourceLoaderFileModule\getStyles
getStyles(ResourceLoaderContext $context)
Get all styles for a given context.
Definition: ResourceLoaderFileModule.php:408
$fallback
$fallback
Definition: MessagesAb.php:11
ResourceLoaderFileModule\getFileHashes
getFileHashes(ResourceLoaderContext $context)
Helper method for getDefinitionSummary.
Definition: ResourceLoaderFileModule.php:535
ResourceLoaderFileModule\$noflip
bool $noflip
Whether CSSJanus flipping should be skipped for this module.
Definition: ResourceLoaderFileModule.php:157
ResourceLoaderFileModule\getScriptURLsForDebug
getScriptURLsForDebug(ResourceLoaderContext $context)
Definition: ResourceLoaderFileModule.php:382
ResourceLoaderFileModule\__construct
__construct(array $options=[], $localBasePath=null, $remoteBasePath=null)
Constructs a new module from an options array.
Definition: ResourceLoaderFileModule.php:196
ResourceLoaderFilePath
An object to represent a path to a JavaScript/CSS file, along with a remote and local base path,...
Definition: ResourceLoaderFilePath.php:28
MediaWiki\Languages\LanguageFallback
Definition: LanguageFallback.php:31
ResourceLoaderFileModule\enableModuleContentVersion
enableModuleContentVersion()
Disable module content versioning.
Definition: ResourceLoaderFileModule.php:525
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
ResourceLoaderFileModule\$debugRaw
bool $debugRaw
Link to raw files in debug mode.
Definition: ResourceLoaderFileModule.php:151
$wgExtensionAssetsPath
$wgExtensionAssetsPath
The URL path of the extensions directory.
Definition: DefaultSettings.php:241
ResourceLoaderFileModule\$hasGeneratedStyles
bool $hasGeneratedStyles
Whether getStyleURLsForDebug should return raw file paths, or return load.php urls.
Definition: ResourceLoaderFileModule.php:163
ResourceLoaderFileModule\$dependencies
array $dependencies
List of modules this module depends on.
Definition: ResourceLoaderFileModule.php:131
ResourceLoaderFileModule\$skinStyles
array $skinStyles
List of paths to CSS files to include when using specific skins.
Definition: ResourceLoaderFileModule.php:101
serialize
serialize()
Definition: ApiMessageTrait.php:138
ResourceLoaderFileModule\getFlip
getFlip(ResourceLoaderContext $context)
Get whether CSS for this module should be flipped.
Definition: ResourceLoaderFileModule.php:1023
ResourceLoaderModule\saveFileDependencies
saveFileDependencies(ResourceLoaderContext $context, array $curFileRefs)
Save the indirect dependencies for this module persuant to the skin/language context.
Definition: ResourceLoaderModule.php:504
ResourceLoaderFileModule\$targets
string[] $targets
Definition: ResourceLoaderFileModule.php:154
$wgStylePath
$wgStylePath
The URL path of the skins directory.
Definition: DefaultSettings.php:226
ResourceLoaderFileModule\getDefinitionSummary
getDefinitionSummary(ResourceLoaderContext $context)
Get the definition summary for this module.
Definition: ResourceLoaderFileModule.php:605
FileContentsHasher\getFileContentsHash
static getFileContentsHash( $filePaths, $algo='md4')
Get a hash of the combined contents of one or more files, either by retrieving a previously-computed ...
Definition: FileContentsHasher.php:88
ResourceLoaderModule\getLessVars
getLessVars(ResourceLoaderContext $context)
Get module-specific LESS variables, if any.
Definition: ResourceLoaderModule.php:691
ResourceLoaderFileModule
Module based on local JavaScript/CSS files.
Definition: ResourceLoaderFileModule.php:39
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:136
ResourceLoaderFileModule\getGroup
getGroup()
Gets the name of the group this module should be loaded in.
Definition: ResourceLoaderFileModule.php:475
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Definition: GlobalFunctions.php:1033
ResourceLoaderModule\getLogger
getLogger()
Definition: ResourceLoaderModule.php:250
ResourceLoaderFileModule\getSkinStyleFiles
getSkinStyleFiles( $skinName)
Gets a list of file paths for all skin styles in the module used by the skin.
Definition: ResourceLoaderFileModule.php:852
ResourceLoaderFileModule\compileLessFile
compileLessFile( $fileName, ResourceLoaderContext $context)
Definition: ResourceLoaderFileModule.php:1065
ResourceLoaderFileModule\getAllStyleFiles
getAllStyleFiles()
Returns all style files and all skin style files used by this module.
Definition: ResourceLoaderFileModule.php:888
ResourceLoaderContext\getDebug
getDebug()
Definition: ResourceLoaderContext.php:238
ResourceLoaderFileModule\processStyle
processStyle( $style, $styleLang, $path, ResourceLoaderContext $context)
Process a CSS/LESS string.
Definition: ResourceLoaderFileModule.php:985
ResourceLoaderFileModule\getStyleURLsForDebug
getStyleURLsForDebug(ResourceLoaderContext $context)
Definition: ResourceLoaderFileModule.php:440
ResourceLoaderFileModule\getRemotePath
getRemotePath( $path)
Definition: ResourceLoaderFileModule.php:699
ResourceLoaderModule\getDeprecationInformation
getDeprecationInformation(ResourceLoaderContext $context)
Get JS representing deprecation information for the current module if available.
Definition: ResourceLoaderModule.php:167
ResourceLoaderFileModule\expandPackageFiles
expandPackageFiles(ResourceLoaderContext $context)
Internal helper for use by getPackageFiles(), getFileHashes() and getDefinitionSummary().
Definition: ResourceLoaderFileModule.php:1182
ResourceLoaderModule\expandRelativePaths
static expandRelativePaths(array $filePaths)
Expand directories relative to $IP.
Definition: ResourceLoaderModule.php:561
ResourceLoaderContext\getLanguage
getLanguage()
Definition: ResourceLoaderContext.php:156
ResourceLoaderFileModule\$messages
array $messages
List of message keys used by this module.
Definition: ResourceLoaderFileModule.php:145
ResourceLoaderModule\getMessageBlob
getMessageBlob(ResourceLoaderContext $context)
Get the hash of the message blob.
Definition: ResourceLoaderModule.php:576
ResourceLoaderFileModule\$languageScripts
array $languageScripts
List of JavaScript files to include when using a specific language.
Definition: ResourceLoaderFileModule.php:65
ResourceLoaderFileModule\stripBom
stripBom( $input)
Takes an input string and removes the UTF-8 BOM character if present.
Definition: ResourceLoaderFileModule.php:1412
ResourceLoaderFileModule\extractBasePaths
static extractBasePaths(array $options=[], $localBasePath=null, $remoteBasePath=null)
Extract a pair of local and remote base paths from module definition information.
Definition: ResourceLoaderFileModule.php:301
ResourceLoaderFileModule\getPackageFiles
getPackageFiles(ResourceLoaderContext $context)
Resolves the package files defintion and generates the content of each package file.
Definition: ResourceLoaderFileModule.php:1319
$content
$content
Definition: router.php:76
ResourceLoaderFileModule\getDependencies
getDependencies(ResourceLoaderContext $context=null)
Gets list of names of modules this module depends on.
Definition: ResourceLoaderFileModule.php:484
CSSMin\getLocalFileReferences
static getLocalFileReferences( $source, $path)
Get a list of local files referenced in a stylesheet (includes non-existent files).
Definition: CSSMin.php:63
ResourceLoaderFileModule\getTargets
getTargets()
Get target(s) for the module, eg ['desktop'] or ['desktop', 'mobile'].
Definition: ResourceLoaderFileModule.php:1032
ResourceLoaderFileModule\$skipFunction
string $skipFunction
File name containing the body of the skip function.
Definition: ResourceLoaderFileModule.php:136
ResourceLoaderFileModule\$group
string $group
Name of group to load this module in.
Definition: ResourceLoaderFileModule.php:148
ResourceLoaderFileModule\$localFileRefs
array $localFileRefs
Place where readStyleFile() tracks file dependencies.
Definition: ResourceLoaderFileModule.php:172
ResourceLoaderFileModule\readScriptFiles
readScriptFiles(array $scripts)
Get the contents of a list of JavaScript files.
Definition: ResourceLoaderFileModule.php:912
ResourceLoaderFileModule\getPath
getPath( $path)
Definition: ResourceLoaderFileModule.php:675
ResourceLoaderFileModule\collateFilePathListByOption
static collateFilePathListByOption(array $list, $option, $default)
Collates file paths by option (where provided).
Definition: ResourceLoaderFileModule.php:742
ResourceLoaderContext\getSkin
getSkin()
Definition: ResourceLoaderContext.php:188
VueComponentParser
Parser for Vue single file components (.vue files).
Definition: VueComponentParser.php:39
ResourceLoaderFileModule\$expandedPackageFiles
array $expandedPackageFiles
Expanded versions of $packageFiles, lazy-computed by expandPackageFiles(); keyed by context hash.
Definition: ResourceLoaderFileModule.php:116
ResourceLoaderFileModule\$localBasePath
string $localBasePath
Local base path, see __construct()
Definition: ResourceLoaderFileModule.php:41
$wgResourceBasePath
$wgResourceBasePath
The default 'remoteBasePath' value for instances of ResourceLoaderFileModule.
Definition: DefaultSettings.php:4105
ResourceLoaderFileModule\getScriptFiles
getScriptFiles(ResourceLoaderContext $context)
Get a list of script file paths for this module, in order of proper execution.
Definition: ResourceLoaderFileModule.php:790
ResourceLoaderFileModule\getStyleSheetLang
getStyleSheetLang( $path)
Infer the stylesheet language from a stylesheet file path.
Definition: ResourceLoaderFileModule.php:714
ResourceLoaderFileModule\getLocalPath
getLocalPath( $path)
Definition: ResourceLoaderFileModule.php:687
ResourceLoaderModule
Abstraction for ResourceLoader modules, with name registration and maxage functionality.
Definition: ResourceLoaderModule.php:39
$cache
$cache
Definition: mcc.php:33
ResourceLoaderFileModule\tryForKey
static tryForKey(array $list, $key, $fallback=null)
Get a list of element that match a key, optionally using a fallback key.
Definition: ResourceLoaderFileModule.php:772
ResourceLoaderFileModule\readStyleFile
readStyleFile( $path, ResourceLoaderContext $context)
Read and process a style file.
Definition: ResourceLoaderFileModule.php:961
ResourceLoaderFileModule\getTemplates
getTemplates()
Takes named templates by the module and returns an array mapping.
Definition: ResourceLoaderFileModule.php:1147
ResourceLoaderFileModule\$fullyExpandedPackageFiles
array $fullyExpandedPackageFiles
Further expanded versions of $expandedPackageFiles, lazy-computed by getPackageFiles(); keyed by cont...
Definition: ResourceLoaderFileModule.php:122
$path
$path
Definition: NoLocalSettings.php:25
ResourceLoaderFileModule\readStyleFiles
readStyleFiles(array $styles, ResourceLoaderContext $context)
Get the contents of a list of CSS files.
Definition: ResourceLoaderFileModule.php:935
ResourceLoaderModule\getRelativePaths
static getRelativePaths(array $filePaths)
Make file paths relative to MediaWiki directory.
Definition: ResourceLoaderModule.php:547
ResourceLoaderModule\getFileDependencies
getFileDependencies(ResourceLoaderContext $context)
Get the indirect dependencies for this module persuant to the skin/language context.
Definition: ResourceLoaderModule.php:465
ResourceLoaderFileModule\$remoteBasePath
string $remoteBasePath
Remote base path, see __construct()
Definition: ResourceLoaderFileModule.php:44
ResourceLoaderFileModule\supportsURLLoading
supportsURLLoading()
Definition: ResourceLoaderFileModule.php:396
ResourceLoaderContext\getHash
getHash()
All factors that uniquely identify this request, except 'modules'.
Definition: ResourceLoaderContext.php:357
ResourceLoaderFileModule\getFileContents
getFileContents( $localPath, $type)
Helper method for getting a file.
Definition: ResourceLoaderFileModule.php:496
ResourceLoaderFileModule\getMessages
getMessages()
Gets list of message keys used by this module.
Definition: ResourceLoaderFileModule.php:466
ResourceLoaderFileModule\getVueComponentParser
getVueComponentParser()
Definition: ResourceLoaderFileModule.php:664
$IP
$IP
Definition: WebStart.php:49
ResourceLoaderFileModule\getAllSkinStyleFiles
getAllSkinStyleFiles()
Gets a list of file paths for all skin style files in the module, for all available skins.
Definition: ResourceLoaderFileModule.php:866
ResourceLoaderFileModule\compileLessString
compileLessString( $style, $stylePath, ResourceLoaderContext $context)
Compile a LESS string into CSS.
Definition: ResourceLoaderFileModule.php:1084
ResourceLoaderFileModule\getStyleFiles
getStyleFiles(ResourceLoaderContext $context)
Get a list of file paths for all styles in this module, in order of proper inclusion.
Definition: ResourceLoaderFileModule.php:834
ResourceLoaderFileModule\getType
getType()
Get the module's load type.
Definition: ResourceLoaderFileModule.php:1042
ResourceLoaderFileModule\getScript
getScript(ResourceLoaderContext $context)
Gets all scripts for a given context concatenated together.
Definition: ResourceLoaderFileModule.php:357
ResourceLoaderFileModule\$scripts
array $scripts
List of paths to JavaScript files to always include.
Definition: ResourceLoaderFileModule.php:56
ResourceLoaderFileModule\getLanguageScripts
getLanguageScripts( $lang)
Get the set of language scripts for the given language, possibly using a fallback language.
Definition: ResourceLoaderFileModule.php:810
ResourceLoaderModule\getConfig
getConfig()
Definition: ResourceLoaderModule.php:221
ResourceLoaderFileModule\$missingLocalFileRefs
array $missingLocalFileRefs
Place where readStyleFile() tracks file dependencies for non-existent files.
Definition: ResourceLoaderFileModule.php:178
OutputPage\transformResourcePath
static transformResourcePath(Config $config, $path)
Transform path to web-accessible static resource.
Definition: OutputPage.php:3951
ResourceLoaderFileModule\$packageFiles
array $packageFiles
List of packaged files to make available through require()
Definition: ResourceLoaderFileModule.php:110
ObjectCache\getLocalServerInstance
static getLocalServerInstance( $fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
Definition: ObjectCache.php:254
ResourceLoaderFileModule\getPackageFileType
static getPackageFileType( $path)
Infer the file type from a package file path.
Definition: ResourceLoaderFileModule.php:723
ResourceLoaderFileModule\$vueComponentParser
VueComponentParser null $vueComponentParser
Lazy-created by getVueComponentParser()
Definition: ResourceLoaderFileModule.php:183
$type
$type
Definition: testCompression.php:52