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 
153  protected $targets = [ 'desktop' ];
154 
156  protected $noflip = false;
157 
162  protected $hasGeneratedStyles = false;
163 
171  protected $localFileRefs = [];
172 
177  protected $missingLocalFileRefs = [];
178 
182  protected $vueComponentParser = null;
183 
195  public function __construct(
196  array $options = [],
197  $localBasePath = null,
198  $remoteBasePath = null
199  ) {
200  // Flag to decide whether to automagically add the mediawiki.template module
201  $hasTemplates = false;
202  // localBasePath and remoteBasePath both have unbelievably long fallback chains
203  // and need to be handled separately.
204  list( $this->localBasePath, $this->remoteBasePath ) =
206 
207  // Extract, validate and normalise remaining options
208  foreach ( $options as $member => $option ) {
209  switch ( $member ) {
210  // Lists of file paths
211  case 'scripts':
212  case 'debugScripts':
213  case 'styles':
214  case 'packageFiles':
215  $this->{$member} = is_array( $option ) ? $option : [ $option ];
216  break;
217  case 'templates':
218  $hasTemplates = true;
219  $this->{$member} = is_array( $option ) ? $option : [ $option ];
220  break;
221  // Collated lists of file paths
222  case 'languageScripts':
223  case 'skinScripts':
224  case 'skinStyles':
225  if ( !is_array( $option ) ) {
226  throw new InvalidArgumentException(
227  "Invalid collated file path list error. " .
228  "'$option' given, array expected."
229  );
230  }
231  foreach ( $option as $key => $value ) {
232  if ( !is_string( $key ) ) {
233  throw new InvalidArgumentException(
234  "Invalid collated file path list key error. " .
235  "'$key' given, string expected."
236  );
237  }
238  $this->{$member}[$key] = is_array( $value ) ? $value : [ $value ];
239  }
240  break;
241  case 'deprecated':
242  $this->deprecated = $option;
243  break;
244  // Lists of strings
245  case 'dependencies':
246  case 'messages':
247  case 'targets':
248  // Normalise
249  $option = array_values( array_unique( (array)$option ) );
250  sort( $option );
251 
252  $this->{$member} = $option;
253  break;
254  // Single strings
255  case 'group':
256  case 'skipFunction':
257  $this->{$member} = (string)$option;
258  break;
259  // Single booleans
260  case 'debugRaw':
261  case 'noflip':
262  $this->{$member} = (bool)$option;
263  break;
264  }
265  }
266  if ( isset( $options['scripts'] ) && isset( $options['packageFiles'] ) ) {
267  throw new InvalidArgumentException( "A module may not set both 'scripts' and 'packageFiles'" );
268  }
269  if ( isset( $options['packageFiles'] ) && isset( $options['skinScripts'] ) ) {
270  throw new InvalidArgumentException( "Options 'skinScripts' and 'packageFiles' cannot be used together." );
271  }
272  if ( $hasTemplates ) {
273  $this->dependencies[] = 'mediawiki.template';
274  // Ensure relevant template compiler module gets loaded
275  foreach ( $this->templates as $alias => $templatePath ) {
276  if ( is_int( $alias ) ) {
277  $alias = $this->getPath( $templatePath );
278  }
279  $suffix = explode( '.', $alias );
280  $suffix = end( $suffix );
281  $compilerModule = 'mediawiki.template.' . $suffix;
282  if ( $suffix !== 'html' && !in_array( $compilerModule, $this->dependencies ) ) {
283  $this->dependencies[] = $compilerModule;
284  }
285  }
286  }
287  }
288 
300  public static function extractBasePaths(
301  array $options = [],
302  $localBasePath = null,
303  $remoteBasePath = null
304  ) {
305  global $IP, $wgResourceBasePath;
306 
307  // The different ways these checks are done, and their ordering, look very silly,
308  // but were preserved for backwards-compatibility just in case. Tread lightly.
309 
310  if ( $localBasePath === null ) {
312  }
313  if ( $remoteBasePath === null ) {
315  }
316 
317  if ( isset( $options['remoteExtPath'] ) ) {
318  global $wgExtensionAssetsPath;
319  $remoteBasePath = $wgExtensionAssetsPath . '/' . $options['remoteExtPath'];
320  }
321 
322  if ( isset( $options['remoteSkinPath'] ) ) {
323  global $wgStylePath;
324  $remoteBasePath = $wgStylePath . '/' . $options['remoteSkinPath'];
325  }
326 
327  if ( array_key_exists( 'localBasePath', $options ) ) {
328  $localBasePath = (string)$options['localBasePath'];
329  }
330 
331  if ( array_key_exists( 'remoteBasePath', $options ) ) {
332  $remoteBasePath = (string)$options['remoteBasePath'];
333  }
334 
335  return [ $localBasePath, $remoteBasePath ];
336  }
337 
344  public function getScript( ResourceLoaderContext $context ) {
345  $deprecationScript = $this->getDeprecationInformation( $context );
346  if ( $this->packageFiles !== null ) {
347  $packageFiles = $this->getPackageFiles( $context );
348  foreach ( $packageFiles['files'] as &$file ) {
349  if ( $file['type'] === 'script+style' ) {
350  $file['content'] = $file['content']['script'];
351  $file['type'] = 'script';
352  }
353  }
354  if ( $deprecationScript ) {
355  $mainFile =& $packageFiles['files'][$packageFiles['main']];
356  $mainFile['content'] = $deprecationScript . $mainFile['content'];
357  }
358  return $packageFiles;
359  }
360 
361  $files = $this->getScriptFiles( $context );
362  return $deprecationScript . $this->readScriptFiles( $files );
363  }
364 
369  public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
370  $urls = [];
371  foreach ( $this->getScriptFiles( $context ) as $file ) {
373  $this->getConfig(),
374  $this->getRemotePath( $file )
375  );
376  }
377  return $urls;
378  }
379 
383  public function supportsURLLoading() {
384  // If package files are involved, don't support URL loading, because that breaks
385  // scoped require() functions
386  return $this->debugRaw && !$this->packageFiles;
387  }
388 
395  public function getStyles( ResourceLoaderContext $context ) {
396  $styles = $this->readStyleFiles(
397  $this->getStyleFiles( $context ),
398  $context
399  );
400 
401  if ( $this->packageFiles !== null ) {
402  $packageFiles = $this->getPackageFiles( $context );
403  foreach ( $packageFiles['files'] as $fileName => $file ) {
404  if ( $file['type'] === 'script+style' ) {
405  $style = $this->processStyle(
406  $file['content']['style'],
407  $file['content']['styleLang'],
408  $fileName,
409  $context
410  );
411  $styles['all'] = ( $styles['all'] ?? '' ) . "\n" . $style;
412  }
413  }
414  }
415 
416  // Track indirect file dependencies so that ResourceLoaderStartUpModule can check for
417  // on-disk file changes to any of this files without having to recompute the file list
418  $this->saveFileDependencies( $context, $this->localFileRefs );
419 
420  return $styles;
421  }
422 
427  public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
428  if ( $this->hasGeneratedStyles ) {
429  // Do the default behaviour of returning a url back to load.php
430  // but with only=styles.
431  return parent::getStyleURLsForDebug( $context );
432  }
433  // Our module consists entirely of real css files,
434  // in debug mode we can load those directly.
435  $urls = [];
436  foreach ( $this->getStyleFiles( $context ) as $mediaType => $list ) {
437  $urls[$mediaType] = [];
438  foreach ( $list as $file ) {
439  $urls[$mediaType][] = OutputPage::transformResourcePath(
440  $this->getConfig(),
441  $this->getRemotePath( $file )
442  );
443  }
444  }
445  return $urls;
446  }
447 
453  public function getMessages() {
454  return $this->messages;
455  }
456 
462  public function getGroup() {
463  return $this->group;
464  }
465 
471  public function getDependencies( ResourceLoaderContext $context = null ) {
472  return $this->dependencies;
473  }
474 
483  private function getFileContents( $localPath, $type ) {
484  if ( !is_file( $localPath ) ) {
485  throw new RuntimeException(
486  __METHOD__ . ": $type file not found, or is not a file: \"$localPath\""
487  );
488  }
489  return $this->stripBom( file_get_contents( $localPath ) );
490  }
491 
497  public function getSkipFunction() {
498  if ( !$this->skipFunction ) {
499  return null;
500  }
501  $localPath = $this->getLocalPath( $this->skipFunction );
502  return $this->getFileContents( $localPath, 'skip function' );
503  }
504 
513  public function enableModuleContentVersion() {
514  return false;
515  }
516 
523  private function getFileHashes( ResourceLoaderContext $context ) {
524  $files = [];
525 
526  // Flatten style files into $files
527  $styles = self::collateFilePathListByOption( $this->styles, 'media', 'all' );
528  foreach ( $styles as $styleFiles ) {
529  $files = array_merge( $files, $styleFiles );
530  }
531 
533  self::tryForKey( $this->skinStyles, $context->getSkin(), 'default' ),
534  'media',
535  'all'
536  );
537  foreach ( $skinFiles as $styleFiles ) {
538  $files = array_merge( $files, $styleFiles );
539  }
540 
541  // Extract file paths for package files
542  // Optimisation: Use foreach() and isset() instead of array_map/array_filter.
543  // This is a hot code path, called by StartupModule for thousands of modules.
544  $expandedPackageFiles = $this->expandPackageFiles( $context );
545  $packageFiles = [];
546  if ( $expandedPackageFiles ) {
547  foreach ( $expandedPackageFiles['files'] as $fileInfo ) {
548  if ( isset( $fileInfo['filePath'] ) ) {
549  $packageFiles[] = $fileInfo['filePath'];
550  }
551  }
552  }
553 
554  // Merge all the file paths we were able discover directly from the module definition.
555  // This is the master list of direct-dependent files for this module.
556  $files = array_merge(
557  $files,
559  $this->scripts,
560  $this->templates,
561  $context->getDebug() ? $this->debugScripts : [],
562  $this->getLanguageScripts( $context->getLanguage() ),
563  self::tryForKey( $this->skinScripts, $context->getSkin(), 'default' )
564  );
565  if ( $this->skipFunction ) {
566  $files[] = $this->skipFunction;
567  }
568 
569  // Expand these local paths into absolute file paths
570  $files = array_map( [ $this, 'getLocalPath' ], $files );
571 
572  // Add any lazily discovered file dependencies from previous module builds.
573  // These are added last because they are already absolute file paths.
574  $files = array_merge( $files, $this->getFileDependencies( $context ) );
575 
576  // Filter out any duplicates. Typically introduced by getFileDependencies() which
577  // may lazily re-discover a master file.
578  $files = array_unique( $files );
579 
580  // Don't return array keys or any other form of file path here, only the hashes.
581  // Including file paths would needlessly cause global cache invalidation when files
582  // move on disk or if e.g. the MediaWiki directory name changes.
583  // Anything where order is significant is already detected by the definition summary.
585  }
586 
593  public function getDefinitionSummary( ResourceLoaderContext $context ) {
594  $summary = parent::getDefinitionSummary( $context );
595 
596  $options = [];
597  foreach ( [
598  // The following properties are omitted because they don't affect the module reponse:
599  // - localBasePath (Per T104950; Changes when absolute directory name changes. If
600  // this affects 'scripts' and other file paths, getFileHashes accounts for that.)
601  // - remoteBasePath (Per T104950)
602  // - dependencies (provided via startup module)
603  // - targets
604  // - group (provided via startup module)
605  'scripts',
606  'debugScripts',
607  'styles',
608  'languageScripts',
609  'skinScripts',
610  'skinStyles',
611  'messages',
612  'templates',
613  'skipFunction',
614  'debugRaw',
615  ] as $member ) {
616  $options[$member] = $this->{$member};
617  }
618 
619  $packageFiles = $this->expandPackageFiles( $context );
620  if ( $packageFiles ) {
621  // Extract the minimum needed:
622  // - The 'main' pointer (included as-is).
623  // - The 'files' array, simplified to only which files exist (the keys of
624  // this array), and something that represents their non-file content.
625  // For packaged files that reflect files directly from disk, the
626  // 'getFileHashes' method tracks their content already.
627  // It is important that the keys of the $packageFiles['files'] array
628  // are preserved, as they do affect the module output.
629  $packageFiles['files'] = array_map( function ( $fileInfo ) {
630  return $fileInfo['definitionSummary'] ?? ( $fileInfo['content'] ?? null );
631  }, $packageFiles['files'] );
632  }
633 
634  $summary[] = [
635  'options' => $options,
636  'packageFiles' => $packageFiles,
637  'fileHashes' => $this->getFileHashes( $context ),
638  'messageBlob' => $this->getMessageBlob( $context ),
639  ];
640 
641  $lessVars = $this->getLessVars( $context );
642  if ( $lessVars ) {
643  $summary[] = [ 'lessVars' => $lessVars ];
644  }
645 
646  return $summary;
647  }
648 
652  protected function getVueComponentParser() {
653  if ( $this->vueComponentParser === null ) {
654  $this->vueComponentParser = new VueComponentParser;
655  }
657  }
658 
663  protected function getPath( $path ) {
664  if ( $path instanceof ResourceLoaderFilePath ) {
665  return $path->getPath();
666  }
667 
668  return $path;
669  }
670 
675  protected function getLocalPath( $path ) {
676  if ( $path instanceof ResourceLoaderFilePath ) {
677  return $path->getLocalPath();
678  }
679 
680  return "{$this->localBasePath}/$path";
681  }
682 
687  protected function getRemotePath( $path ) {
688  if ( $path instanceof ResourceLoaderFilePath ) {
689  return $path->getRemotePath();
690  }
691 
692  return "{$this->remoteBasePath}/$path";
693  }
694 
702  public function getStyleSheetLang( $path ) {
703  return preg_match( '/\.less$/i', $path ) ? 'less' : 'css';
704  }
705 
711  public static function getPackageFileType( $path ) {
712  if ( preg_match( '/\.json$/i', $path ) ) {
713  return 'data';
714  }
715  if ( preg_match( '/\.vue$/i', $path ) ) {
716  return 'script-vue';
717  }
718  return 'script';
719  }
720 
730  protected static function collateFilePathListByOption( array $list, $option, $default ) {
731  $collatedFiles = [];
732  foreach ( $list as $key => $value ) {
733  if ( is_int( $key ) ) {
734  // File name as the value
735  if ( !isset( $collatedFiles[$default] ) ) {
736  $collatedFiles[$default] = [];
737  }
738  $collatedFiles[$default][] = $value;
739  } elseif ( is_array( $value ) ) {
740  // File name as the key, options array as the value
741  $optionValue = $value[$option] ?? $default;
742  if ( !isset( $collatedFiles[$optionValue] ) ) {
743  $collatedFiles[$optionValue] = [];
744  }
745  $collatedFiles[$optionValue][] = $key;
746  }
747  }
748  return $collatedFiles;
749  }
750 
760  protected static function tryForKey( array $list, $key, $fallback = null ) {
761  if ( isset( $list[$key] ) && is_array( $list[$key] ) ) {
762  return $list[$key];
763  } elseif ( is_string( $fallback )
764  && isset( $list[$fallback] )
765  && is_array( $list[$fallback] )
766  ) {
767  return $list[$fallback];
768  }
769  return [];
770  }
771 
778  private function getScriptFiles( ResourceLoaderContext $context ) {
779  $files = array_merge(
780  $this->scripts,
781  $this->getLanguageScripts( $context->getLanguage() ),
782  self::tryForKey( $this->skinScripts, $context->getSkin(), 'default' )
783  );
784  if ( $context->getDebug() ) {
785  $files = array_merge( $files, $this->debugScripts );
786  }
787 
788  return array_unique( $files, SORT_REGULAR );
789  }
790 
798  private function getLanguageScripts( $lang ) {
799  $scripts = self::tryForKey( $this->languageScripts, $lang );
800  if ( $scripts ) {
801  return $scripts;
802  }
803  $fallbacks = MediaWikiServices::getInstance()->getLanguageFallback()
804  ->getAll( $lang, LanguageFallback::MESSAGES );
805  foreach ( $fallbacks as $lang ) {
806  $scripts = self::tryForKey( $this->languageScripts, $lang );
807  if ( $scripts ) {
808  return $scripts;
809  }
810  }
811 
812  return [];
813  }
814 
822  public function getStyleFiles( ResourceLoaderContext $context ) {
823  return array_merge_recursive(
824  self::collateFilePathListByOption( $this->styles, 'media', 'all' ),
825  self::collateFilePathListByOption(
826  self::tryForKey( $this->skinStyles, $context->getSkin(), 'default' ),
827  'media',
828  'all'
829  )
830  );
831  }
832 
840  protected function getSkinStyleFiles( $skinName ) {
842  self::tryForKey( $this->skinStyles, $skinName ),
843  'media',
844  'all'
845  );
846  }
847 
854  protected function getAllSkinStyleFiles() {
855  $styleFiles = [];
856  $internalSkinNames = array_keys( Skin::getSkinNames() );
857  $internalSkinNames[] = 'default';
858 
859  foreach ( $internalSkinNames as $internalSkinName ) {
860  $styleFiles = array_merge_recursive(
861  $styleFiles,
862  $this->getSkinStyleFiles( $internalSkinName )
863  );
864  }
865 
866  return $styleFiles;
867  }
868 
874  public function getAllStyleFiles() {
875  $collatedStyleFiles = array_merge_recursive(
876  self::collateFilePathListByOption( $this->styles, 'media', 'all' ),
877  $this->getAllSkinStyleFiles()
878  );
879 
880  $result = [];
881 
882  foreach ( $collatedStyleFiles as $media => $styleFiles ) {
883  foreach ( $styleFiles as $styleFile ) {
884  $result[] = $this->getLocalPath( $styleFile );
885  }
886  }
887 
888  return $result;
889  }
890 
898  private function readScriptFiles( array $scripts ) {
899  if ( empty( $scripts ) ) {
900  return '';
901  }
902  $js = '';
903  foreach ( array_unique( $scripts, SORT_REGULAR ) as $fileName ) {
904  $localPath = $this->getLocalPath( $fileName );
905  $contents = $this->getFileContents( $localPath, 'script' );
906  $js .= $contents . "\n";
907  }
908  return $js;
909  }
910 
921  public function readStyleFiles( array $styles, ResourceLoaderContext $context ) {
922  if ( !$styles ) {
923  return [];
924  }
925  foreach ( $styles as $media => $files ) {
926  $uniqueFiles = array_unique( $files, SORT_REGULAR );
927  $styleFiles = [];
928  foreach ( $uniqueFiles as $file ) {
929  $styleFiles[] = $this->readStyleFile( $file, $context );
930  }
931  $styles[$media] = implode( "\n", $styleFiles );
932  }
933  return $styles;
934  }
935 
947  protected function readStyleFile( $path, ResourceLoaderContext $context ) {
948  $localPath = $this->getLocalPath( $path );
949  $style = $this->getFileContents( $localPath, 'style' );
950  $styleLang = $this->getStyleSheetLang( $localPath );
951 
952  return $this->processStyle( $style, $styleLang, $path, $context );
953  }
954 
971  protected function processStyle( $style, $styleLang, $path, ResourceLoaderContext $context ) {
972  $localPath = $this->getLocalPath( $path );
973  $remotePath = $this->getRemotePath( $path );
974 
975  if ( $styleLang === 'less' ) {
976  $style = $this->compileLessString( $style, $localPath, $context );
977  $this->hasGeneratedStyles = true;
978  }
979 
980  if ( $this->getFlip( $context ) ) {
981  $style = CSSJanus::transform(
982  $style,
983  /* $swapLtrRtlInURL = */ true,
984  /* $swapLeftRightInURL = */ false
985  );
986  }
987 
988  $localDir = dirname( $localPath );
989  $remoteDir = dirname( $remotePath );
990  // Get and register local file references
991  $localFileRefs = CSSMin::getLocalFileReferences( $style, $localDir );
992  foreach ( $localFileRefs as $file ) {
993  if ( file_exists( $file ) ) {
994  $this->localFileRefs[] = $file;
995  } else {
996  $this->missingLocalFileRefs[] = $file;
997  }
998  }
999  // Don't cache this call. remap() ensures data URIs embeds are up to date,
1000  // and urls contain correct content hashes in their query string. (T128668)
1001  return CSSMin::remap( $style, $localDir, $remoteDir, true );
1002  }
1003 
1009  public function getFlip( ResourceLoaderContext $context ) {
1010  return $context->getDirection() === 'rtl' && !$this->noflip;
1011  }
1012 
1018  public function getTargets() {
1019  return $this->targets;
1020  }
1021 
1028  public function getType() {
1029  $canBeStylesOnly = !(
1030  // All options except 'styles', 'skinStyles' and 'debugRaw'
1031  $this->scripts
1032  || $this->debugScripts
1033  || $this->templates
1034  || $this->languageScripts
1035  || $this->skinScripts
1036  || $this->dependencies
1037  || $this->messages
1038  || $this->skipFunction
1040  );
1041  return $canBeStylesOnly ? self::LOAD_STYLES : self::LOAD_GENERAL;
1042  }
1043 
1051  protected function compileLessFile( $fileName, ResourceLoaderContext $context ) {
1052  wfDeprecated( __METHOD__, '1.35' );
1053 
1054  $style = $this->getFileContents( $fileName, 'LESS' );
1055  return $this->compileLessString( $style, $fileName, $context );
1056  }
1057 
1070  protected function compileLessString( $style, $stylePath, ResourceLoaderContext $context ) {
1071  static $cache;
1072  // @TODO: dependency injection
1073  if ( !$cache ) {
1075  }
1076 
1077  $vars = $this->getLessVars( $context );
1078  // Construct a cache key from a hash of the LESS source, and a hash digest
1079  // of the LESS variables used for compilation.
1080  ksort( $vars );
1081  $key = $cache->makeGlobalKey(
1082  'resourceloader-less',
1083  'v1',
1084  hash( 'md4', $style ),
1085  hash( 'md4', serialize( $vars ) )
1086  );
1087 
1088  // If we got a cached value, we have to validate it by getting a checksum of all the
1089  // files that were loaded by the parser and ensuring it matches the cached entry's.
1090  $data = $cache->get( $key );
1091  if (
1092  !$data ||
1093  $data['hash'] !== FileContentsHasher::getFileContentsHash( $data['files'] )
1094  ) {
1095  $compiler = $context->getResourceLoader()->getLessCompiler( $vars );
1096  $css = $compiler->parse( $style, $stylePath )->getCss();
1097  // T253055: store the implicit dependency paths in a form relative to any install
1098  // path so that multiple version of the application can share the cache for identical
1099  // less stylesheets. This also avoids churn during application updates.
1100  $files = $compiler->AllParsedFiles();
1101  $data = [
1102  'css' => $css,
1103  'files' => ResourceLoaderModule::getRelativePaths( $files ),
1104  'hash' => FileContentsHasher::getFileContentsHash( $files )
1105  ];
1106  $cache->set( $key, $data, $cache::TTL_DAY );
1107  }
1108 
1109  foreach ( ResourceLoaderModule::expandRelativePaths( $data['files'] ) as $path ) {
1110  $this->localFileRefs[] = $path;
1111  }
1112 
1113  return $data['css'];
1114  }
1115 
1121  public function getTemplates() {
1122  $templates = [];
1123 
1124  foreach ( $this->templates as $alias => $templatePath ) {
1125  // Alias is optional
1126  if ( is_int( $alias ) ) {
1127  $alias = $this->getPath( $templatePath );
1128  }
1129  $localPath = $this->getLocalPath( $templatePath );
1130  $content = $this->getFileContents( $localPath, 'template' );
1131 
1132  $templates[$alias] = $this->stripBom( $content );
1133  }
1134  return $templates;
1135  }
1136 
1156  private function expandPackageFiles( ResourceLoaderContext $context ) {
1157  $hash = $context->getHash();
1158  if ( isset( $this->expandedPackageFiles[$hash] ) ) {
1159  return $this->expandedPackageFiles[$hash];
1160  }
1161  if ( $this->packageFiles === null ) {
1162  return null;
1163  }
1164  $expandedFiles = [];
1165  $mainFile = null;
1166 
1167  foreach ( $this->packageFiles as $key => $fileInfo ) {
1168  if ( is_string( $fileInfo ) ) {
1169  $fileInfo = [ 'name' => $fileInfo, 'file' => $fileInfo ];
1170  }
1171  if ( !isset( $fileInfo['name'] ) ) {
1172  $msg = "Missing 'name' key in package file info for module '{$this->getName()}'," .
1173  " offset '{$key}'.";
1174  $this->getLogger()->error( $msg );
1175  throw new LogicException( $msg );
1176  }
1177  $fileName = $fileInfo['name'];
1178 
1179  // Infer type from alias if needed
1180  $type = $fileInfo['type'] ?? self::getPackageFileType( $fileName );
1181  $expanded = [ 'type' => $type ];
1182  if ( !empty( $fileInfo['main'] ) ) {
1183  $mainFile = $fileName;
1184  if ( $type !== 'script' && $type !== 'script-vue' ) {
1185  $msg = "Main file in package must be of type 'script', module " .
1186  "'{$this->getName()}', main file '{$mainFile}' is '{$type}'.";
1187  $this->getLogger()->error( $msg );
1188  throw new LogicException( $msg );
1189  }
1190  }
1191 
1192  // Perform expansions (except 'file' and 'callback'), creating one of these keys:
1193  // - 'content': literal value.
1194  // - 'filePath': content to be read from a file.
1195  // - 'callback': content computed by a callable.
1196  if ( isset( $fileInfo['content'] ) ) {
1197  $expanded['content'] = $fileInfo['content'];
1198  } elseif ( isset( $fileInfo['file'] ) ) {
1199  $expanded['filePath'] = $fileInfo['file'];
1200  } elseif ( isset( $fileInfo['callback'] ) ) {
1201  // If no extra parameter for the callback is given, use null.
1202  $expanded['callbackParam'] = $fileInfo['callbackParam'] ?? null;
1203 
1204  if ( !is_callable( $fileInfo['callback'] ) ) {
1205  $msg = "Invalid 'callback' for module '{$this->getName()}', file '{$fileName}'.";
1206  $this->getLogger()->error( $msg );
1207  throw new LogicException( $msg );
1208  }
1209  if ( isset( $fileInfo['versionCallback'] ) ) {
1210  if ( !is_callable( $fileInfo['versionCallback'] ) ) {
1211  throw new LogicException( "Invalid 'versionCallback' for "
1212  . "module '{$this->getName()}', file '{$fileName}'."
1213  );
1214  }
1215 
1216  // Execute the versionCallback with the same arguments that
1217  // would be given to the callback
1218  $callbackResult = ( $fileInfo['versionCallback'] )(
1219  $context,
1220  $this->getConfig(),
1221  $expanded['callbackParam']
1222  );
1223  if ( $callbackResult instanceof ResourceLoaderFilePath ) {
1224  $expanded['filePath'] = $callbackResult->getPath();
1225  } else {
1226  $expanded['definitionSummary'] = $callbackResult;
1227  }
1228  // Don't invoke 'callback' here as it may be expensive (T223260).
1229  $expanded['callback'] = $fileInfo['callback'];
1230  } else {
1231  // Else go ahead invoke callback with its arguments.
1232  $callbackResult = ( $fileInfo['callback'] )(
1233  $context,
1234  $this->getConfig(),
1235  $expanded['callbackParam']
1236  );
1237  if ( $callbackResult instanceof ResourceLoaderFilePath ) {
1238  $expanded['filePath'] = $callbackResult->getPath();
1239  } else {
1240  $expanded['content'] = $callbackResult;
1241  }
1242  }
1243  } elseif ( isset( $fileInfo['config'] ) ) {
1244  if ( $type !== 'data' ) {
1245  $msg = "Key 'config' only valid for data files. "
1246  . " Module '{$this->getName()}', file '{$fileName}' is '{$type}'.";
1247  $this->getLogger()->error( $msg );
1248  throw new LogicException( $msg );
1249  }
1250  $expandedConfig = [];
1251  foreach ( $fileInfo['config'] as $key => $var ) {
1252  $expandedConfig[ is_numeric( $key ) ? $var : $key ] = $this->getConfig()->get( $var );
1253  }
1254  $expanded['content'] = $expandedConfig;
1255  } elseif ( !empty( $fileInfo['main'] ) ) {
1256  // [ 'name' => 'foo.js', 'main' => true ] is shorthand
1257  $expanded['filePath'] = $fileName;
1258  } else {
1259  $msg = "Incomplete definition for module '{$this->getName()}', file '{$fileName}'. "
1260  . "One of 'file', 'content', 'callback', or 'config' must be set.";
1261  $this->getLogger()->error( $msg );
1262  throw new LogicException( $msg );
1263  }
1264 
1265  $expandedFiles[$fileName] = $expanded;
1266  }
1267 
1268  if ( $expandedFiles && $mainFile === null ) {
1269  // The first package file that is a script is the main file
1270  foreach ( $expandedFiles as $path => $file ) {
1271  if ( $file['type'] === 'script' || $file['type'] === 'script-vue' ) {
1272  $mainFile = $path;
1273  break;
1274  }
1275  }
1276  }
1277 
1278  $result = [
1279  'main' => $mainFile,
1280  'files' => $expandedFiles
1281  ];
1282 
1283  $this->expandedPackageFiles[$hash] = $result;
1284  return $result;
1285  }
1286 
1293  public function getPackageFiles( ResourceLoaderContext $context ) {
1294  if ( $this->packageFiles === null ) {
1295  return null;
1296  }
1297  $hash = $context->getHash();
1298  if ( isset( $this->fullyExpandedPackageFiles[ $hash ] ) ) {
1299  return $this->fullyExpandedPackageFiles[ $hash ];
1300  }
1301  $expandedPackageFiles = $this->expandPackageFiles( $context );
1302 
1303  // Expand file contents
1304  foreach ( $expandedPackageFiles['files'] as $fileName => &$fileInfo ) {
1305  // Turn any 'filePath' or 'callback' key into actual 'content',
1306  // and remove the key after that. The callback could return a
1307  // ResourceLoaderFilePath object; if that happens, fall through
1308  // to the 'filePath' handling.
1309  if ( isset( $fileInfo['callback'] ) ) {
1310  $callbackResult = ( $fileInfo['callback'] )(
1311  $context,
1312  $this->getConfig(),
1313  $fileInfo['callbackParam']
1314  );
1315  if ( $callbackResult instanceof ResourceLoaderFilePath ) {
1316  // Fall through to the filePath handling code below
1317  $fileInfo['filePath'] = $callbackResult->getPath();
1318  } else {
1319  $fileInfo['content'] = $callbackResult;
1320  }
1321  unset( $fileInfo['callback'] );
1322  }
1323  // Only interpret 'filePath' if 'content' hasn't been set already.
1324  // This can happen if 'versionCallback' provided 'filePath',
1325  // while 'callback' provides 'content'. In that case both are set
1326  // at this point. The 'filePath' from 'versionCallback' in that case is
1327  // only to inform getDefinitionSummary().
1328  if ( !isset( $fileInfo['content'] ) && isset( $fileInfo['filePath'] ) ) {
1329  $localPath = $this->getLocalPath( $fileInfo['filePath'] );
1330  $content = $this->getFileContents( $localPath, 'package' );
1331  if ( $fileInfo['type'] === 'data' ) {
1332  $content = json_decode( $content );
1333  }
1334  $fileInfo['content'] = $content;
1335  unset( $fileInfo['filePath'] );
1336  }
1337  if ( $fileInfo['type'] === 'script-vue' ) {
1338  try {
1339  $parsedComponent = $this->getVueComponentParser()->parse(
1340  $fileInfo['content'],
1341  [ 'minifyTemplate' => !$context->getDebug() ]
1342  );
1343  } catch ( Exception $e ) {
1344  $msg = "Error parsing file '$fileName' in module '{$this->getName()}': " .
1345  $e->getMessage();
1346  $this->getLogger()->error( $msg );
1347  throw new RuntimeException( $msg );
1348  }
1349  $encodedTemplate = json_encode( $parsedComponent['template'] );
1350  if ( $context->getDebug() ) {
1351  // Replace \n (backslash-n) with space + backslash-newline in debug mode
1352  // We only replace \n if not preceded by a backslash, to avoid breaking '\\n'
1353  $encodedTemplate = preg_replace( '/(?<!\\\\)\\\\n/', " \\\n", $encodedTemplate );
1354  // Expand \t to real tabs in debug mode
1355  $encodedTemplate = strtr( $encodedTemplate, [ "\\t" => "\t" ] );
1356  }
1357  $fileInfo['content'] = [
1358  'script' => $parsedComponent['script'] .
1359  ";\nmodule.exports.template = $encodedTemplate;",
1360  'style' => $parsedComponent['style'] ?? '',
1361  'styleLang' => $parsedComponent['styleLang'] ?? 'css'
1362  ];
1363  $fileInfo['type'] = 'script+style';
1364  }
1365 
1366  // Not needed for client response, exists for use by getDefinitionSummary().
1367  unset( $fileInfo['definitionSummary'] );
1368  // Not needed for client response, used by callbacks only.
1369  unset( $fileInfo['callbackParam'] );
1370  }
1371 
1372  $this->fullyExpandedPackageFiles[ $hash ] = $expandedPackageFiles;
1373  return $expandedPackageFiles;
1374  }
1375 
1386  protected function stripBom( $input ) {
1387  if ( substr_compare( "\xef\xbb\xbf", $input, 0, 3 ) === 0 ) {
1388  return substr( $input, 3 );
1389  }
1390  return $input;
1391  }
1392 }
ResourceLoaderFileModule\getSkipFunction
getSkipFunction()
Get the skip function.
Definition: ResourceLoaderFileModule.php:497
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:172
ResourceLoaderFileModule\$debugScripts
array $debugScripts
List of paths to JavaScript files to include in debug mode.
Definition: ResourceLoaderFileModule.php:83
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:154
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
ResourceLoaderContext\getResourceLoader
getResourceLoader()
Definition: ResourceLoaderContext.php:121
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:395
$fallback
$fallback
Definition: MessagesAb.php:11
ResourceLoaderFileModule\getFileHashes
getFileHashes(ResourceLoaderContext $context)
Helper method for getDefinitionSummary.
Definition: ResourceLoaderFileModule.php:523
ResourceLoaderFileModule\$noflip
bool $noflip
Whether CSSJanus flipping should be skipped for this module.
Definition: ResourceLoaderFileModule.php:156
ResourceLoaderFileModule\getScriptURLsForDebug
getScriptURLsForDebug(ResourceLoaderContext $context)
Definition: ResourceLoaderFileModule.php:369
ResourceLoaderFileModule\__construct
__construct(array $options=[], $localBasePath=null, $remoteBasePath=null)
Constructs a new module from an options array.
Definition: ResourceLoaderFileModule.php:195
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:513
$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:244
ResourceLoaderFileModule\$hasGeneratedStyles
bool $hasGeneratedStyles
Whether getStyleURLsForDebug should return raw file paths, or return load.php urls.
Definition: ResourceLoaderFileModule.php:162
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:1009
ResourceLoaderModule\saveFileDependencies
saveFileDependencies(ResourceLoaderContext $context, array $curFileRefs)
Save the indirect dependencies for this module persuant to the skin/language context.
Definition: ResourceLoaderModule.php:501
$wgStylePath
$wgStylePath
The URL path of the skins directory.
Definition: DefaultSettings.php:229
ResourceLoaderFileModule\getDefinitionSummary
getDefinitionSummary(ResourceLoaderContext $context)
Get the definition summary for this module.
Definition: ResourceLoaderFileModule.php:593
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
Skin\getSkinNames
static getSkinNames()
Fetch the set of available skins.
Definition: Skin.php:66
ResourceLoaderModule\getLessVars
getLessVars(ResourceLoaderContext $context)
Get module-specific LESS variables, if any.
Definition: ResourceLoaderModule.php:688
ResourceLoaderFileModule
Module based on local JavaScript/CSS files.
Definition: ResourceLoaderFileModule.php:39
ResourceLoaderFileModule\getGroup
getGroup()
Gets the name of the group this module should be loaded in.
Definition: ResourceLoaderFileModule.php:462
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Definition: GlobalFunctions.php:1026
ResourceLoaderModule\getLogger
getLogger()
Definition: ResourceLoaderModule.php:247
ResourceLoaderFileModule\getSkinStyleFiles
getSkinStyleFiles( $skinName)
Gets a list of file paths for all skin styles in the module used by the skin.
Definition: ResourceLoaderFileModule.php:840
ResourceLoaderFileModule\compileLessFile
compileLessFile( $fileName, ResourceLoaderContext $context)
Definition: ResourceLoaderFileModule.php:1051
ResourceLoaderFileModule\getAllStyleFiles
getAllStyleFiles()
Returns all style files and all skin style files used by this module.
Definition: ResourceLoaderFileModule.php:874
ResourceLoaderContext\getDebug
getDebug()
Definition: ResourceLoaderContext.php:236
ResourceLoaderFileModule\processStyle
processStyle( $style, $styleLang, $path, ResourceLoaderContext $context)
Process a CSS/LESS string.
Definition: ResourceLoaderFileModule.php:971
ResourceLoaderFileModule\getStyleURLsForDebug
getStyleURLsForDebug(ResourceLoaderContext $context)
Definition: ResourceLoaderFileModule.php:427
ResourceLoaderFileModule\getRemotePath
getRemotePath( $path)
Definition: ResourceLoaderFileModule.php:687
ResourceLoaderModule\getDeprecationInformation
getDeprecationInformation(ResourceLoaderContext $context)
Get JS representing deprecation information for the current module if available.
Definition: ResourceLoaderModule.php:164
ResourceLoaderFileModule\$targets
$targets
Definition: ResourceLoaderFileModule.php:153
ResourceLoaderFileModule\expandPackageFiles
expandPackageFiles(ResourceLoaderContext $context)
Internal helper for use by getPackageFiles(), getFileHashes() and getDefinitionSummary().
Definition: ResourceLoaderFileModule.php:1156
ResourceLoaderModule\expandRelativePaths
static expandRelativePaths(array $filePaths)
Expand directories relative to $IP.
Definition: ResourceLoaderModule.php:558
ResourceLoaderContext\getLanguage
getLanguage()
Definition: ResourceLoaderContext.php:154
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:573
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:1386
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:300
ResourceLoaderFileModule\getPackageFiles
getPackageFiles(ResourceLoaderContext $context)
Resolves the package files defintion and generates the content of each package file.
Definition: ResourceLoaderFileModule.php:1293
$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:471
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:1018
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:171
CACHE_ANYTHING
const CACHE_ANYTHING
Definition: Defines.php:90
ResourceLoaderFileModule\readScriptFiles
readScriptFiles(array $scripts)
Get the contents of a list of JavaScript files.
Definition: ResourceLoaderFileModule.php:898
ResourceLoaderFileModule\getPath
getPath( $path)
Definition: ResourceLoaderFileModule.php:663
ResourceLoaderFileModule\collateFilePathListByOption
static collateFilePathListByOption(array $list, $option, $default)
Collates file paths by option (where provided).
Definition: ResourceLoaderFileModule.php:730
ResourceLoaderContext\getSkin
getSkin()
Definition: ResourceLoaderContext.php:186
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:4094
ResourceLoaderFileModule\getScriptFiles
getScriptFiles(ResourceLoaderContext $context)
Get a list of script file paths for this module, in order of proper execution.
Definition: ResourceLoaderFileModule.php:778
ResourceLoaderFileModule\getStyleSheetLang
getStyleSheetLang( $path)
Infer the stylesheet language from a stylesheet file path.
Definition: ResourceLoaderFileModule.php:702
ResourceLoaderFileModule\getLocalPath
getLocalPath( $path)
Definition: ResourceLoaderFileModule.php:675
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:760
ResourceLoaderFileModule\readStyleFile
readStyleFile( $path, ResourceLoaderContext $context)
Read and process a style file.
Definition: ResourceLoaderFileModule.php:947
ResourceLoaderFileModule\getTemplates
getTemplates()
Takes named templates by the module and returns an array mapping.
Definition: ResourceLoaderFileModule.php:1121
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:921
ResourceLoaderModule\getRelativePaths
static getRelativePaths(array $filePaths)
Make file paths relative to MediaWiki directory.
Definition: ResourceLoaderModule.php:544
ResourceLoaderModule\getFileDependencies
getFileDependencies(ResourceLoaderContext $context)
Get the indirect dependencies for this module persuant to the skin/language context.
Definition: ResourceLoaderModule.php:462
ResourceLoaderFileModule\$remoteBasePath
string $remoteBasePath
Remote base path, see __construct()
Definition: ResourceLoaderFileModule.php:44
ResourceLoaderFileModule\supportsURLLoading
supportsURLLoading()
Definition: ResourceLoaderFileModule.php:383
ResourceLoaderContext\getHash
getHash()
All factors that uniquely identify this request, except 'modules'.
Definition: ResourceLoaderContext.php:355
ResourceLoaderFileModule\getFileContents
getFileContents( $localPath, $type)
Helper method for getting a file.
Definition: ResourceLoaderFileModule.php:483
ResourceLoaderFileModule\getMessages
getMessages()
Gets list of message keys used by this module.
Definition: ResourceLoaderFileModule.php:453
ResourceLoaderFileModule\getVueComponentParser
getVueComponentParser()
Definition: ResourceLoaderFileModule.php:652
$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:854
ResourceLoaderFileModule\compileLessString
compileLessString( $style, $stylePath, ResourceLoaderContext $context)
Compile a LESS string into CSS.
Definition: ResourceLoaderFileModule.php:1070
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:822
ResourceLoaderFileModule\getType
getType()
Get the module's load type.
Definition: ResourceLoaderFileModule.php:1028
ResourceLoaderFileModule\getScript
getScript(ResourceLoaderContext $context)
Gets all scripts for a given context concatenated together.
Definition: ResourceLoaderFileModule.php:344
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:798
ResourceLoaderModule\getConfig
getConfig()
Definition: ResourceLoaderModule.php:218
ResourceLoaderFileModule\$missingLocalFileRefs
array $missingLocalFileRefs
Place where readStyleFile() tracks file dependencies for non-existent files.
Definition: ResourceLoaderFileModule.php:177
OutputPage\transformResourcePath
static transformResourcePath(Config $config, $path)
Transform path to web-accessible static resource.
Definition: OutputPage.php:3932
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:711
ResourceLoaderFileModule\$vueComponentParser
VueComponentParser null $vueComponentParser
Lazy-created by getVueComponentParser()
Definition: ResourceLoaderFileModule.php:182
$type
$type
Definition: testCompression.php:52