]> source.dussan.org Git - nextcloud-server.git/commitdiff
feat(template): Allow `JSResourceLocator` to find ES6 scripts
authorFerdinand Thiessen <rpm@fthiessen.de>
Tue, 10 Jan 2023 00:11:34 +0000 (01:11 +0100)
committerFerdinand Thiessen <rpm@fthiessen.de>
Wed, 22 Feb 2023 20:19:37 +0000 (21:19 +0100)
Enable module js (ES6) support on the `JSResourceLocator`.
This changes `JSResourceLocator` to look for `.mjs` files first
to allow applications to provide a fallback `.js` for older Nextcloud versions.

Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
lib/private/Template/JSResourceLocator.php
tests/lib/Template/JSResourceLocatorTest.php

index 0745451bbd5a764f06be7d34ba283b386fc289f6..4b41e51ae146423a5bf9bc3bc00b05f2bbe5c09a 100644 (file)
@@ -59,27 +59,27 @@ class JSResourceLocator extends ResourceLocator {
                        // For language files we try to load them all, so themes can overwrite
                        // single l10n strings without having to translate all of them.
                        $found = 0;
-                       $found += $this->appendIfExist($this->serverroot, 'core/'.$script.'.js');
-                       $found += $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js');
-                       $found += $this->appendIfExist($this->serverroot, $script.'.js');
-                       $found += $this->appendIfExist($this->serverroot, $theme_dir.$script.'.js');
-                       $found += $this->appendIfExist($this->serverroot, 'apps/'.$script.'.js');
-                       $found += $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.'.js');
+                       $found += $this->appendScriptIfExist($this->serverroot, 'core/'.$script);
+                       $found += $this->appendScriptIfExist($this->serverroot, $theme_dir.'core/'.$script);
+                       $found += $this->appendScriptIfExist($this->serverroot, $script);
+                       $found += $this->appendScriptIfExist($this->serverroot, $theme_dir.$script);
+                       $found += $this->appendScriptIfExist($this->serverroot, 'apps/'.$script);
+                       $found += $this->appendScriptIfExist($this->serverroot, $theme_dir.'apps/'.$script);
 
                        if ($found) {
                                return;
                        }
-               } elseif ($this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$script.'.js')
-                       || $this->appendIfExist($this->serverroot, $theme_dir.$script.'.js')
-                       || $this->appendIfExist($this->serverroot, $script.'.js')
-                       || $this->appendIfExist($this->serverroot, $theme_dir . "dist/$app-$scriptName.js")
-                       || $this->appendIfExist($this->serverroot, "dist/$app-$scriptName.js")
-                       || $this->appendIfExist($this->serverroot, 'apps/'.$script.'.js')
+               } elseif ($this->appendScriptIfExist($this->serverroot, $theme_dir.'apps/'.$script)
+                       || $this->appendScriptIfExist($this->serverroot, $theme_dir.$script)
+                       || $this->appendScriptIfExist($this->serverroot, $script)
+                       || $this->appendScriptIfExist($this->serverroot, $theme_dir."dist/$app-$scriptName")
+                       || $this->appendScriptIfExist($this->serverroot, "dist/$app-$scriptName")
+                       || $this->appendScriptIfExist($this->serverroot, 'apps/'.$script)
                        || $this->cacheAndAppendCombineJsonIfExist($this->serverroot, $script.'.json')
-                       || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js')
-                       || $this->appendIfExist($this->serverroot, 'core/'.$script.'.js')
-                       || (strpos($scriptName, '/') === -1 && ($this->appendIfExist($this->serverroot, $theme_dir . "dist/core-$scriptName.js")
-                               || $this->appendIfExist($this->serverroot, "dist/core-$scriptName.js")))
+                       || $this->appendScriptIfExist($this->serverroot, $theme_dir.'core/'.$script)
+                       || $this->appendScriptIfExist($this->serverroot, 'core/'.$script)
+                       || (strpos($scriptName, '/') === -1 && ($this->appendScriptIfExist($this->serverroot, $theme_dir."dist/core-$scriptName")
+                               || $this->appendScriptIfExist($this->serverroot, "dist/core-$scriptName")))
                        || $this->cacheAndAppendCombineJsonIfExist($this->serverroot, 'core/'.$script.'.json')
                ) {
                        return;
@@ -107,7 +107,7 @@ class JSResourceLocator extends ResourceLocator {
 
                // missing translations files fill be ignored
                if (strpos($script, 'l10n/') === 0) {
-                       $this->appendIfExist($app_path, $script . '.js', $app_url);
+                       $this->appendScriptIfExist($app_path, $script, $app_url);
                        return;
                }
 
@@ -130,6 +130,17 @@ class JSResourceLocator extends ResourceLocator {
        public function doFindTheme($script) {
        }
 
+       /**
+        * Try to find ES6 script file (`.mjs`) with fallback to plain javascript (`.js`)
+        * @see appendIfExist()
+        */
+       protected function appendScriptIfExist($root, $file, $webRoot = null) {
+               if (!$this->appendIfExist($root, $file . '.mjs', $webRoot)) {
+                       return $this->appendIfExist($root, $file . '.js', $webRoot);
+               }
+               return true;
+       }
+
        protected function cacheAndAppendCombineJsonIfExist($root, $file, $app = 'core') {
                if (is_file($root.'/'.$file)) {
                        if ($this->jsCombiner->process($root, $file, $app)) {
index 20fd79a91b5af1d6df6754cfe9834f63e442d62e..627fe676680e3286670d40e86022a0815cd55bb5 100644 (file)
@@ -26,6 +26,7 @@ namespace Test\Template;
 use OC\SystemConfig;
 use OC\Template\JSCombiner;
 use OC\Template\JSResourceLocator;
+use OCP\App\IAppManager;
 use OCP\Files\IAppData;
 use OCP\ICacheFactory;
 use OCP\IURLGenerator;
@@ -42,6 +43,8 @@ class JSResourceLocatorTest extends \Test\TestCase {
        protected $cacheFactory;
        /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
        protected $logger;
+       /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */
+       protected $appManager;
 
        protected function setUp(): void {
                parent::setUp();
@@ -51,6 +54,7 @@ class JSResourceLocatorTest extends \Test\TestCase {
                $this->config = $this->createMock(SystemConfig::class);
                $this->cacheFactory = $this->createMock(ICacheFactory::class);
                $this->logger = $this->createMock(LoggerInterface::class);
+               $this->appManager = $this->createMock(IAppManager::class);
        }
 
        private function jsResourceLocator() {
@@ -63,7 +67,8 @@ class JSResourceLocatorTest extends \Test\TestCase {
                );
                return new JSResourceLocator(
                        $this->logger,
-                       $jsCombiner
+                       $jsCombiner,
+                       $this->appManager,
                );
        }
 
@@ -84,25 +89,34 @@ class JSResourceLocatorTest extends \Test\TestCase {
        }
 
        public function testFindWithAppPathSymlink() {
+               $appName = 'test-js-app';
+
                // First create new apps path, and a symlink to it
                $apps_dirname = $this->randomString();
                $new_apps_path = sys_get_temp_dir() . '/' . $apps_dirname;
                $new_apps_path_symlink = $new_apps_path . '_link';
-               mkdir($new_apps_path);
-               symlink($apps_dirname, $new_apps_path_symlink);
+               $this->assertTrue((
+                       mkdir($new_apps_path) && symlink($apps_dirname, $new_apps_path_symlink)
+               ), 'Setup of apps path failed');
 
                // Create an app within that path
-               mkdir($new_apps_path . '/' . 'test-js-app');
+               $this->assertTrue((
+                       mkdir($new_apps_path . '/' . $appName) && touch($new_apps_path . '/' . $appName . '/' . 'test-file.js')
+               ), 'Setup of app within the new apps path failed');
 
                // Use the symlink as the app path
-               \OC::$APPSROOTS[] = [
-                       'path' => $new_apps_path_symlink,
-                       'url' => '/js-apps-test',
-                       'writable' => false,
-               ];
-
+               $this->appManager->expects($this->once())
+                       ->method('getAppPath')
+                       ->with($appName)
+                       ->willReturn("$new_apps_path_symlink/$appName");
+               $this->appManager->expects($this->once())
+                       ->method('getAppWebPath')
+                       ->with($appName)
+                       ->willReturn("/js-apps-test/$appName");
+
+               // Run the tests
                $locator = $this->jsResourceLocator();
-               $locator->find(['test-js-app/test-file']);
+               $locator->find(["$appName/test-file"]);
 
                $resources = $locator->getResources();
                $this->assertCount(1, $resources);
@@ -122,7 +136,45 @@ class JSResourceLocatorTest extends \Test\TestCase {
                $this->assertEquals($expectedFile, $file);
 
                array_pop(\OC::$APPSROOTS);
-               unlink($new_apps_path_symlink);
+               //unlink($new_apps_path_symlink);
+               //$this->rrmdir($new_apps_path);
+       }
+
+       public function testFindModuleJSWithFallback() {
+               // First create new apps path, and a symlink to it
+               $apps_dirname = $this->randomString();
+               $new_apps_path = sys_get_temp_dir() . '/' . $apps_dirname;
+               mkdir($new_apps_path);
+
+               // Create an app within that path
+               mkdir("$new_apps_path/test-js-app");
+               touch("$new_apps_path/test-js-app/module.mjs");
+               touch("$new_apps_path/test-js-app/both.mjs");
+               touch("$new_apps_path/test-js-app/both.js");
+               touch("$new_apps_path/test-js-app/plain.js");
+
+               // Use the app path
+               $this->appManager->expects($this->any())
+                       ->method('getAppPath')
+                       ->with('test-js-app')
+                       ->willReturn("$new_apps_path/test-js-app");
+
+               $locator = $this->jsResourceLocator();
+               $locator->find(['test-js-app/module', 'test-js-app/both', 'test-js-app/plain']);
+
+               $resources = $locator->getResources();
+               $this->assertCount(3, $resources);
+
+               $expectedRoot = $new_apps_path . '/test-js-app';
+               $expectedWebRoot = \OC::$WEBROOT . '/js-apps-test/test-js-app';
+               $expectedFiles = ['module.mjs', 'both.mjs', 'plain.js'];
+
+               for ($idx = 0; $idx++; $idx < 3) {
+                       $this->assertEquals($expectedWebRoot, $resources[$idx][1]);
+                       $this->assertEquals($expectedFiles[$idx], $resources[$idx][2]);
+               }
+               
+               array_pop(\OC::$APPSROOTS);
                $this->rrmdir($new_apps_path);
        }
 }