├── .editorconfig ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── .travis.yml ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── codecov.yml ├── deploy_key.enc ├── docs └── api.json ├── intern.json ├── package-lock.json ├── package.json ├── src ├── interfaces.d.ts └── loader.ts ├── tests ├── common │ ├── a │ │ ├── app.js │ │ ├── map2.js │ │ ├── relative1.js │ │ └── remappedApp.js │ ├── amd │ │ └── onlyFactory.js │ ├── app.js │ ├── commonJs │ │ ├── Deep2.js │ │ ├── app.js │ │ ├── app1.js │ │ ├── circular1.js │ │ ├── circular2.js │ │ ├── deep1.js │ │ ├── deep3.js │ │ ├── deep4.js │ │ ├── testModule1.js │ │ ├── testModule2.js │ │ └── testModule3.js │ ├── map1.js │ ├── plugin.js │ ├── pluginConfig.js │ ├── recursive │ │ ├── a.js │ │ ├── b.js │ │ ├── c.js │ │ ├── d.js │ │ └── e.js │ └── usesApp.js ├── functional │ ├── all.ts │ ├── amdApp │ │ ├── Deep2.ts │ │ ├── app.ts │ │ ├── app1.js │ │ ├── circular1.ts │ │ ├── circular2.ts │ │ ├── crossOrigin.js │ │ ├── deep1.ts │ │ ├── deep3.ts │ │ ├── deep4.ts │ │ ├── module1.js │ │ ├── module2.js │ │ ├── module3.js │ │ └── module4.js │ ├── amdFactoryOnly.html │ ├── amdModuleCircular.html │ ├── amdModuleCircular2.html │ ├── amdModuleCircular3.html │ ├── amdModuleDeepDeps.html │ ├── amdModuleWithId1.html │ ├── amdModuleWithId1a.html │ ├── amdModuleWithId2.html │ ├── amdModuleWithId2a.html │ ├── amdModuleWithId3.html │ ├── amdModuleWithId3a.html │ ├── amdModuleWithId4.html │ ├── amdModuleWithId4a.html │ ├── amdModuleWithId5.html │ ├── amdModuleWithId6.html │ ├── amdModuleWithId6a.html │ ├── basicAmdLoading.html │ ├── basicAmdLoading.ts │ ├── basicCommonJsLoading.html │ ├── basicCommonJsLoading.ts │ ├── commonJsModuleCircular.html │ ├── commonJsModuleCircular2.html │ ├── commonJsModuleCircular3.html │ ├── commonJsModuleDeepDeps.html │ ├── commonJsModuleWithId1.html │ ├── commonJsModuleWithId2.html │ ├── commonJsModuleWithId3.html │ ├── commonJsModuleWithId4.html │ ├── crossOrigin.ts │ ├── crossOriginAnon.html │ ├── crossOriginCreds.html │ ├── crossOriginFalse.html │ ├── csp-cdn.html │ ├── csp-cdn.ts │ ├── csp-simple.html │ ├── csp-simple.ts │ ├── csp-success.html │ ├── csp.ts │ ├── executeTest.ts │ ├── map.html │ ├── require │ │ ├── config │ │ │ ├── baseUrl.html │ │ │ ├── defaultConfig.html │ │ │ ├── map-hierarchy.html │ │ │ ├── map-merge.html │ │ │ ├── map-nested.html │ │ │ ├── map-plugin.html │ │ │ ├── map-relative.html │ │ │ ├── map-simple.html │ │ │ ├── map-star.html │ │ │ ├── packages1.html │ │ │ ├── packages2.html │ │ │ ├── packages3.html │ │ │ ├── packages4.html │ │ │ ├── paths1.html │ │ │ └── pkg │ │ │ │ └── main.js │ │ ├── has.html │ │ ├── on │ │ │ ├── error.html │ │ │ └── remove.html │ │ ├── plugin-config.html │ │ ├── plugin-load.html │ │ ├── require.ts │ │ ├── toAbsMid.html │ │ ├── toUrl.html │ │ └── undef.html │ ├── scriptConfigReading.html │ ├── scriptConfigReading.ts │ ├── shimAmdLoading.html │ ├── shimAmdLoading.ts │ ├── shimAmdLoading2.html │ ├── webworkerAmd.ts │ ├── webworkerBasic.html │ └── worker.ts ├── interfaces.d.ts ├── module.d.ts ├── run.html ├── support │ └── util.ts ├── tsconfig.json └── unit │ ├── all-node.ts │ ├── all.ts │ ├── bad-module.js │ ├── basicCommonJsLoading.ts │ ├── require.ts │ └── simpleTest.js ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [{package.json,.travis.yml}] 16 | indent_style = space 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case users don't have core.autocrlf set 2 | * text=auto 3 | 4 | # Files that should always be normalized and converted to native line 5 | # endings on checkout. 6 | *.js text 7 | *.json text 8 | *.ts text 9 | *.md text 10 | *.yml text 11 | LICENSE text 12 | 13 | # Files that are truly binary and should not be modified 14 | *.png binary 15 | *.jpg binary 16 | *.jpeg binary 17 | *.gif binary 18 | *.jar binary 19 | *.zip binary 20 | *.psd binary 21 | *.enc binary 22 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Thank You 2 | 3 | We very much welcome contributions to Dojo 2. 4 | 5 | Because we have so many repositories that are part of Dojo 2, we have located our [Contributing Guidelines](https://github.com/dojo/meta/blob/master/CONTRIBUTING.md) in our [Dojo 2 Meta Repository](https://github.com/dojo/meta#readme). 6 | 7 | Look forward to working with you on Dojo 2!!! 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | **Bug / Enhancement** 13 | 14 | 15 | 16 | Package Version: 17 | 18 | **Code** 19 | 20 | 21 | 22 | **Expected behavior:** 23 | 24 | 25 | 26 | **Actual behavior:** 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Type:** bug / feature 2 | 3 | The following has been addressed in the PR: 4 | 5 | * [ ] There is a related issue 6 | * [ ] All code has been formatted with [`prettier`](https://prettier.io/) as per the [readme code style guidelines](./../#code-style) 7 | * [ ] Unit or Functional tests are included in the PR 8 | 9 | 17 | 18 | **Description:** 19 | 20 | Resolves #??? 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .sublimets 2 | .tscache 3 | *.js 4 | *.js.map 5 | !/*.js 6 | !tests/**/*.js 7 | !tasks/**/*.js 8 | /typings 9 | dist 10 | _build 11 | node_modules 12 | bower_components 13 | tests/typings/dist/ 14 | .baseDir.ts 15 | /html-report 16 | coverage-final.lcov 17 | /_apidoc 18 | deploy_key 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /_build 2 | /support 3 | /tests 4 | /typings 5 | .editorconfig 6 | .gitattributes 7 | .gitignore 8 | .npmignore 9 | .travis.yml 10 | Gruntfile.js 11 | coverage-final.lcov 12 | coverage-unmapped.json 13 | tsconfig.json 14 | tslint.json 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '6' 5 | env: 6 | global: 7 | - SAUCE_USERNAME: dojo2-ts-ci 8 | - SAUCE_ACCESS_KEY: e92610e3-834e-4bec-a3b5-6f7b9d874601 9 | - BROWSERSTACK_USERNAME: dylanschiemann2 10 | - BROWSERSTACK_ACCESS_KEY: 4Q2g8YAc9qeZzB2hECnS 11 | before_install: 12 | - if [ ${TRAVIS_BRANCH-""} == "master" ] && [ -n ${encrypted_12c8071d2874_key-""} 13 | ]; then openssl aes-256-cbc -K $encrypted_12c8071d2874_key -iv $encrypted_12c8071d2874_iv 14 | -in deploy_key.enc -out deploy_key -d; fi 15 | install: 16 | - travis_retry npm install grunt-cli 17 | - travis_retry npm install 18 | script: 19 | - grunt 20 | - grunt intern:browserstack --test-reporter 21 | - grunt uploadCoverage 22 | - grunt dist 23 | - grunt doc 24 | notifications: 25 | slack: 26 | secure: QL+qrf9Y8h/v7WLu9rVRd6pU5CQSIKjaBeknyGtpCBpKW8suWQroSk0NmIRmH3//IHHd1VXIOsHC3wQVceAmktij1q9qaDqD1269G4+BRLJ9D7IaRlaayVIhZxd7FKEkPH9iSADg2vtN7i5NDoORqwp6BKMCMUMusPu1ME+gc4r98EjmKJ7u7Nh2sr0+jqWGttBGJ30yah7Uq+i6Cy9gUnKm4O5tP+emp0pRfZNpT8Ekyrjc0ZnKOrmgxvywVlEZaPnMoOWOWcxj/ZQSgP+0NeQ6pkSnLPA6X+tA9OinI3WiWvQTUTOfYEiLp7oOol6yuEghKR4dL5xSemy4cOMCHys1Ar754AYH9e7UReSTdFRm5/FRpH5TRDVqqbQ8BvZPBwP/qXRD1kxRf8QFrLOI+evSaFQSBoXpcquE0/ZDwC3GEn4vi0gOmxpXakUspoORGVTWCABIa639jm47wInClK5QNPtg++JytXIeQUufiFCqLy/IWKE/HiGkotYLf7jI61XabSY6yXC6lQ06UyZyD6WHp+v1Yw85oaovaYxPhHOFwmXUYGIIxwaK9NSBG6P7wuJJKHl6dnmXFrIsJYZVZZBMJuT8iapC9ogohnX4WPRnf8bTuaPFAM4++t/jZvHS4MhVBoMaaAc38J/GDicY9JrMn5xW8r1HEQDMIZKaOVE= 27 | on_success: change 28 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | The [Contributing Guidelines](https://github.com/dojo/meta/blob/master/CONTRIBUTING.md) 2 | for all Dojo 2 packages can be found in the [Dojo 2 Meta Repository](https://github.com/dojo/meta#readme). 3 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* jshint node:true */ 2 | 3 | module.exports = function (grunt) { 4 | grunt.loadNpmTasks('grunt-contrib-uglify'); 5 | grunt.loadNpmTasks('dts-generator'); 6 | 7 | require('grunt-dojo2').initConfig(grunt, { 8 | dtsGenerator: { 9 | options: { 10 | baseDir: 'src', 11 | name: 'dojo-loader' 12 | }, 13 | dist: { 14 | options: { 15 | out: 'dist/umd/dojo-loader.d.ts' 16 | }, 17 | src: [ '<%= skipTests %>' ] 18 | } 19 | }, 20 | 21 | /* loader has to build in a slightly different way than the standard Dojo 2 package */ 22 | ts: { 23 | tests: { 24 | compilerOptions: { 25 | module: 'umd' 26 | }, 27 | include: [ 'tests/**/*.ts', 'typings/index.d.ts', 'src/interfaces.d.ts' ] 28 | }, 29 | dist: { 30 | compilerOptions: { 31 | declaration: false, 32 | rootDir: 'src' 33 | } 34 | } 35 | }, 36 | 37 | typedoc: { 38 | options: { 39 | ignoreCompilerErrors: true // Remove this once compile errors are resolved 40 | } 41 | }, 42 | 43 | /* loader has minification built into the package, eventually this should be moved to grunt-dojo2 */ 44 | uglify: { 45 | dist: { 46 | options: { 47 | banner: '/*! <%= name %>@<%= version %> - Copyright (c) 2016, The Dojo Foundation. ' + 48 | 'All rights reserved. */', 49 | sourceMap: true, 50 | sourceMapName: 'dist/umd/loader.min.js.map', 51 | sourceMapIncludeSources: true, 52 | sourceMapIn: 'dist/umd/loader.js.map', 53 | compress: { 54 | dead_code: true, 55 | unsafe: true 56 | } 57 | }, 58 | files: { 59 | 'dist/umd/loader.min.js': 'dist/umd/loader.js' 60 | } 61 | } 62 | }, 63 | 64 | intern: { 65 | version: 4 66 | } 67 | }); 68 | 69 | /* we have to write the dev task from the default because of the need to copy compile the tests differently */ 70 | grunt.registerTask('dev', [ 71 | 'typings:dev', 72 | 'tslint', 73 | 'clean:dev', 74 | 'dojo-ts:dev', 75 | 'dojo-ts:tests', 76 | 'copy:staticTestFiles' 77 | ]); 78 | 79 | /* we also have to add the uglify task */ 80 | grunt.registerTask('dist', grunt.config.get('distTasks').concat(['uglify:dist', 'dtsGenerator:dist'])); 81 | }; 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The "New" BSD License 2 | ********************* 3 | 4 | Copyright (c) 2015-2017, [JS Foundation](https://js.foundation/) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | * Neither the name of the JS Foundation nor the names of its contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @dojo/loader 2 | 3 | 4 | [![Build Status](https://travis-ci.org/dojo/loader.svg?branch=master)](https://travis-ci.org/dojo/loader) 5 | [![codecov.io](http://codecov.io/github/dojo/loader/coverage.svg?branch=master)](http://codecov.io/github/dojo/loader?branch=master) 6 | [![npm version](https://badge.fury.io/js/%40dojo%2Floader.svg)](https://badge.fury.io/js/%40dojo%2Floader) 7 | 8 | This package provides a JavaScript AMD loader useful in applications running in either a web browser, node.js or nashorn. 9 | 10 | `@dojo/loader` does not have any dependencies on a JavaScript framework. 11 | 12 | - [Usage](#usage) 13 | - [Support](#support) 14 | - [Features](#features) 15 | - [How do I contribute?](#how-do-i-contribute) 16 | - [Code Style](#code-style) 17 | - [Installation](#installation) 18 | - [Testing](#testing) 19 | - [Licensing information](#licensing-information) 20 | 21 | ## Note 22 | 23 | 24 | We strongly recommend using the `@dojo/cli` build tools for a Dojo 2 application over a runtime loader such as `@dojo/loader`. 25 | 26 | ## Usage 27 | 28 | To use `@dojo/loader`, install the package: 29 | 30 | ```bash 31 | npm install @dojo/loader 32 | ``` 33 | 34 | ## Support 35 | 36 | | Environment | Version | 37 | |---------------|----------:| 38 | | IE | 10+ | 39 | | Firefox | 30+ | 40 | | Chrome | 30+ | 41 | | Opera | 15+ | 42 | | Safari | 8, 9 | 43 | | Android | 4.4+ | 44 | | iOS | 7+ | 45 | | Node | 0.12+ | 46 | | Nashorn | 1.8+ | 47 | 48 | ## Features 49 | 50 | - AMD loading 51 | - CJS loading (in a node environment) 52 | - Plugins: 53 | - [text](https://github.com/dojo/core/blob/master/src/text.ts) 54 | - [has](https://github.com/dojo/core/blob/master/src/has.ts) 55 | - Loading in a Nashorn environment 56 | 57 | Use a script tag to import the loader. This will make `require` and `define` available in the global namespace. 58 | 59 | ``` html 60 | 61 | ``` 62 | 63 | The loader can load both AMD and CJS formatted modules. 64 | 65 | There is no need to use the Dojo 1.x method of requiring node modules via `dojo/node!` plugin anymore. 66 | 67 | ## How do I contribute? 68 | 69 | We appreciate your interest! Please see the [Guidelines Repository](https://github.com/dojo/guidelines#readme) for the 70 | Contributing Guidelines. 71 | 72 | ### Code Style 73 | 74 | This repository uses [`prettier`](https://prettier.io/) for code styling rules and formatting. A pre-commit hook is installed automatically and configured to run `prettier` against all staged files as per the configuration in the project's `package.json`. 75 | 76 | An additional npm script to run `prettier` (with write set to `true`) against all `src` and `test` project files is available by running: 77 | 78 | ```bash 79 | npm run prettier 80 | ``` 81 | 82 | ### Installation 83 | 84 | To start working with this package, clone the repository and run `npm install`. 85 | 86 | In order to build the project run `grunt dev` or `grunt dist`. 87 | 88 | ### Testing 89 | 90 | Test cases MUST be written using Intern using the Object test interface and Assert assertion interface. 91 | 92 | 90% branch coverage MUST be provided for all code submitted to this repository, as reported by istanbul’s combined coverage results for all supported platforms. 93 | 94 | ## Licensing information 95 | 96 | © 2004–2018 [JS Foundation](https://js.foundation/) & contributors. [New BSD](http://opensource.org/licenses/BSD-3-Clause) license. 97 | 98 | 103 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | fixes: 2 | - "_build/::" 3 | coverage: 4 | notify: 5 | slack: 6 | default: 7 | url: "secret:s0/VflRMgHsftySwh6fwCN0LmIG3OtUt+21uJBS6E8qd7QIzRLvNdOwYipBwWb5ME1uFxNDrEqh5Giu0qlTAWALYP3N8HyTUU6te1eEchIJuMkmk174Uq0FH7c99sBbUQPt2xVWUcdTNAYCc4BJmXaYqCg7DSK5XCKBgLi9XP4c=" 8 | threshold: 2 9 | attachments: "sunburst, diff" 10 | -------------------------------------------------------------------------------- /deploy_key.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dojo/loader/147cb45a67a4de9a411c388af0047ae8bdd4d5aa/deploy_key.enc -------------------------------------------------------------------------------- /docs/api.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 0, 3 | "name": "@dojo/loader", 4 | "kind": 0, 5 | "flags": { 6 | "__visited__": true 7 | }, 8 | "children": [ 9 | { 10 | "id": 1, 11 | "name": "\"loader\"", 12 | "kind": 1, 13 | "kindString": "External module", 14 | "flags": { 15 | "isExported": true, 16 | "__visited__": true 17 | }, 18 | "originalName": "src/loader.ts", 19 | "children": [ 20 | { 21 | "id": 2, 22 | "name": "Packages", 23 | "kind": 32, 24 | "kindString": "Variable", 25 | "flags": { 26 | "__visited__": true 27 | }, 28 | "sources": [ 29 | { 30 | "fileName": "loader.ts", 31 | "line": 7, 32 | "character": 20 33 | } 34 | ], 35 | "type": { 36 | "type": "union", 37 | "types": [ 38 | { 39 | "type": "reflection", 40 | "declaration": { 41 | "id": 3, 42 | "name": "__type", 43 | "kind": 65536, 44 | "kindString": "Type literal", 45 | "flags": { 46 | "__visited__": true 47 | }, 48 | "indexSignature": [ 49 | { 50 | "id": 4, 51 | "name": "__index", 52 | "kind": 8192, 53 | "kindString": "Index signature", 54 | "flags": { 55 | "__visited__": true 56 | }, 57 | "parameters": [ 58 | { 59 | "id": 5, 60 | "name": "key", 61 | "kind": 32768, 62 | "kindString": "Parameter", 63 | "flags": { 64 | "__visited__": true 65 | }, 66 | "type": { 67 | "type": "intrinsic", 68 | "name": "string" 69 | } 70 | } 71 | ], 72 | "type": { 73 | "type": "intrinsic", 74 | "name": "any" 75 | } 76 | } 77 | ], 78 | "sources": [ 79 | { 80 | "fileName": "loader.ts", 81 | "line": 7, 82 | "character": 21 83 | } 84 | ] 85 | } 86 | }, 87 | { 88 | "type": "intrinsic", 89 | "name": "undefined" 90 | } 91 | ] 92 | } 93 | } 94 | ], 95 | "groups": [ 96 | { 97 | "title": "Variables", 98 | "kind": 32, 99 | "children": [ 100 | 2 101 | ] 102 | } 103 | ], 104 | "sources": [ 105 | { 106 | "fileName": "loader.ts", 107 | "line": 1, 108 | "character": 0 109 | } 110 | ] 111 | } 112 | ], 113 | "groups": [ 114 | { 115 | "title": "External modules", 116 | "kind": 1, 117 | "children": [ 118 | 1 119 | ] 120 | } 121 | ] 122 | } -------------------------------------------------------------------------------- /intern.json: -------------------------------------------------------------------------------- 1 | { 2 | "capabilities+": { 3 | "project": "Dojo 2", 4 | "name": "@dojo/loader", 5 | "fixSessionCapabilities": false, 6 | "browserstack.debug": false 7 | }, 8 | 9 | "environments": [ 10 | { "browserName": "node" } 11 | ], 12 | 13 | "suites": [ 14 | "./_build/tests/unit/all.js" 15 | ], 16 | 17 | "functionalSuites": [ 18 | "./_build/tests/functional/all.js" 19 | ], 20 | 21 | "browser": { 22 | "loader": { 23 | "script": "dojo2", 24 | "options": { 25 | "packages": [ 26 | { "name": "src", "location": "_build/src" }, 27 | { "name": "tests", "location": "_build/tests" }, 28 | { "name": "@dojo", "location": "node_modules/@dojo" }, 29 | { "name": "sinon", "location": "node_modules/sinon/pkg", "main": "sinon" } 30 | ] 31 | } 32 | } 33 | }, 34 | 35 | "node": { 36 | "suites": [ 37 | "./_build/tests/unit/all-node.js" 38 | ] 39 | }, 40 | 41 | "coverage": [ 42 | "./_build/src/**/*.js" 43 | ], 44 | 45 | "configs": { 46 | "browserstack": { 47 | "tunnel": "browserstack", 48 | "environments+": [ 49 | { "browserName": "internet explorer", "version": "11" }, 50 | { "browserName": "edge" }, 51 | { "browserName": "firefox", "platform": "WINDOWS" }, 52 | { "browserName": "chrome", "platform": "WINDOWS" } 53 | ], 54 | 55 | "maxConcurrency": 5 56 | }, 57 | 58 | "local": { 59 | "tunnel": "selenium", 60 | "tunnelOptions": { 61 | "hostname": "localhost", 62 | "port": 4444 63 | }, 64 | 65 | "environments+": [ 66 | { "browserName": "chrome" } 67 | ] 68 | }, 69 | 70 | "saucelabs": { 71 | "tunnel": "saucelabs", 72 | "tunnelOptions": {}, 73 | 74 | "defaultTimeout": 10000, 75 | "environments+": [ 76 | { "browserName": "internet explorer", "version": [ "11.0" ], "platform": "Windows 7" }, 77 | { "browserName": "firefox", "version": "43", "platform": "Windows 10" }, 78 | { "browserName": "chrome", "platform": "Windows 10" } 79 | ], 80 | "maxConcurrency": 4 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dojo/loader", 3 | "version": "2.0.1-pre", 4 | "description": "JavaScript module loader for web applications.", 5 | "engines": { 6 | "npm": ">=3.0.0" 7 | }, 8 | "homepage": "https://dojo.io", 9 | "bugs": { 10 | "url": "https://github.com/dojo/loader/issues" 11 | }, 12 | "license": "BSD-3-Clause", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/dojo/loader.git" 16 | }, 17 | "main": "loader.js", 18 | "private": true, 19 | "scripts": { 20 | "precommit": "lint-staged", 21 | "prettier": "prettier --write 'src/**/*.ts' 'tests/**/*.ts'", 22 | "test": "grunt test" 23 | }, 24 | "typings": "dojo-loader.d.ts", 25 | "devDependencies": { 26 | "@dojo/loader": "0.1.1", 27 | "@types/glob": "~5.0.0", 28 | "@types/grunt": "~0.4.0", 29 | "@types/node": "~9.6.5", 30 | "dts-generator": "~2.0.0", 31 | "grunt": "^1.0.1", 32 | "grunt-contrib-uglify": "^2.0.0", 33 | "grunt-dojo2": "latest", 34 | "grunt-tslint": "5.0.1", 35 | "husky": "0.14.3", 36 | "intern": "~4.1.0", 37 | "lint-staged": "6.0.0", 38 | "prettier": "1.9.2", 39 | "tslint": "5.8.0", 40 | "typescript": "~2.6.1" 41 | }, 42 | "lint-staged": { 43 | "*.{ts,tsx}": [ 44 | "prettier --write", 45 | "git add" 46 | ] 47 | }, 48 | "prettier": { 49 | "singleQuote": true, 50 | "tabWidth": 4, 51 | "useTabs": true, 52 | "parser": "typescript", 53 | "printWidth": 120, 54 | "arrowParens": "always" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/interfaces.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace DojoLoader { 2 | /** 3 | * Common AMD Configuration 4 | * 5 | * See [Common Config](https://github.com/amdjs/amdjs-api/blob/master/CommonConfig.md) 6 | */ 7 | export interface Config { 8 | /** 9 | * Indicates the root used for ID-to-path resolutions. Relative paths are relative to the current 10 | * working directory. In web browsers, the current working directory is the directory containing 11 | * the web page running the script. 12 | */ 13 | baseUrl?: string; 14 | 15 | /** 16 | * Specifies for a given module ID prefix, what module ID prefix to use in place of another 17 | * module ID prefix. For example, how to express "when `bar` asks for module ID `foo`, 18 | * actually use module ID 'foo1.2'". 19 | * 20 | * This sort of capability is important for larger projects which may have two sets of 21 | * modules that need to use two different versions of `foo`, but they still need to 22 | * cooperate with each other. 23 | * 24 | * This is different from `paths` config. `paths` is only for setting up root paths for 25 | * module IDs, not for mapping one module ID to another one. 26 | */ 27 | map?: ModuleMap; 28 | 29 | /** 30 | * Array of package configuration (packageConfig) objects. Package configuration is for 31 | * traditional CommonJS packages, which has different path lookup rules than the default 32 | * ID-to-path lookup rules used by an AMD loader. 33 | * 34 | * Default lookup rules are ,baseUrl + 'module/id' + .js, where paths config can be used 35 | * to map part of 'module/id' to another path. 36 | */ 37 | packages?: Package[]; 38 | 39 | /** 40 | * For specifying a path for a the given module ID prefix. 41 | * 42 | * A property in the paths object is an absolute module ID prefix. 43 | */ 44 | paths?: { [path: string]: string }; 45 | 46 | /* TODO: We should remove internal APIs like this */ 47 | pkgs?: { [path: string]: Package }; 48 | 49 | shim?: { [path: string]: ModuleShim | string[] }; 50 | 51 | crossOrigin?: false | 'anonymous' | 'use-credentials'; 52 | } 53 | 54 | interface Define { 55 | (moduleId: string, dependencies: string[], factory: Factory): void; 56 | (dependencies: string[], factory: Factory): void; 57 | (factory: Factory): void; 58 | (value: any): void; 59 | amd: { [prop: string]: string | number | boolean }; 60 | } 61 | 62 | interface Factory { 63 | (...modules: any[]): any; 64 | } 65 | 66 | interface Has { 67 | (name: string): any; 68 | add( 69 | name: string, 70 | value: (global: Window, document?: HTMLDocument, element?: HTMLDivElement) => any, 71 | now?: boolean, 72 | force?: boolean 73 | ): void; 74 | add(name: string, value: any, now?: boolean, force?: boolean): void; 75 | } 76 | 77 | interface LoaderError extends Error { 78 | readonly src: string; 79 | readonly info: { module: Module; url: string; parentMid: string; details?: string }; 80 | } 81 | 82 | /** 83 | * AMD Loader Plugin API 84 | * 85 | * See [Loader Plugin API](https://github.com/amdjs/amdjs-api/blob/master/LoaderPlugins.md) 86 | */ 87 | interface LoaderPlugin { 88 | /** 89 | * A function that is called to load a resource. This is the only mandatory API method that needs 90 | * to be implemented for the plugin to be useful, assuming the resource IDs do not need special 91 | * ID normalization. 92 | * @param resourceId The resource ID that the plugin should load. This ID MUST be normalized. 93 | * @param require A local require function to use to load other modules. This require function 94 | * has some utilities on it: 95 | * * **require.toUrl('moduleId+extension')** See the `require.toUrl` API notes 96 | * for more information. 97 | * @param load A function to call once the value of the resource ID has been determined. This 98 | * tells the loader that the plugin is done loading the resource. 99 | * @param config A configuration object. This is a way for the optimizer and the web app to 100 | * pass configuration information to the plugin. An optimization tool may set 101 | * an `isBuild` property in the config to true if this plugin is being called 102 | * as part of an optimizer build. 103 | */ 104 | load?( 105 | resourceId: string, 106 | require: Require, 107 | load: (value?: any) => void, 108 | config?: { [prop: string]: any } 109 | ): void; 110 | 111 | /** 112 | * A function to normalize the passed-in resource ID. Normalization of an module ID normally 113 | * means converting relative paths, like `./some/path` or `../another/path` to be non-relative, 114 | * absolute IDs 115 | * @param resourceId The resource ID to normalize. 116 | * @param normalize A normalization function that accepts a string ID to normalize using the 117 | * standard relative module normalization rules using the loader's current 118 | * configuration. 119 | */ 120 | normalize?(resourceId: string, normalize: (moduleId: string) => string): string; 121 | } 122 | 123 | interface MapItem extends Array { 124 | /* prefix */ 0: string; 125 | /* replacement */ 1: any; 126 | /* regExp */ 2: RegExp; 127 | /* length */ 3: number; 128 | } 129 | 130 | interface MapReplacement extends MapItem { 131 | /* replacement */ 1: string; 132 | } 133 | 134 | interface MapRoot extends Array { 135 | star?: MapSource; 136 | } 137 | 138 | interface MapSource extends MapItem { 139 | /* replacement */ 1: MapReplacement[]; 140 | } 141 | 142 | // TODO are we still abbreviating these properties? 143 | // TODO shouldn't extend for LoaderPlugin because technically `load` is not optional 144 | interface Module extends LoaderPlugin { 145 | cjs: { 146 | exports: any; 147 | id: string; 148 | setExports: (exports: any) => void; 149 | uri: string; 150 | }; 151 | def: Factory; 152 | deps: Module[]; 153 | executed: any; // TODO: enum 154 | injected: boolean; 155 | fix?: (module: Module) => void; 156 | gc: boolean; 157 | mid: string; 158 | pack: Package; 159 | req: Require; 160 | require?: Require; // TODO: WTF? 161 | result: any; 162 | url: string; 163 | 164 | // plugin interface 165 | loadQ?: Module[]; 166 | plugin?: Module; 167 | prid: string; 168 | } 169 | 170 | interface ModuleDefinitionArguments extends Array { 171 | 0: string[]; 172 | 1: Factory; 173 | } 174 | 175 | interface ModuleMap extends ModuleMapItem { 176 | [sourceMid: string]: ModuleMapReplacement | string; 177 | } 178 | 179 | interface ModuleMapItem { 180 | [mid: string]: /* ModuleMapReplacement | ModuleMap */ any; 181 | } 182 | 183 | interface ModuleMapReplacement extends ModuleMapItem { 184 | [findMid: string]: /* replaceMid */ string; 185 | } 186 | 187 | interface ObjectMap { 188 | [key: string]: any; 189 | } 190 | 191 | interface Package { 192 | location?: string; 193 | main?: string; 194 | name?: string; 195 | } 196 | 197 | interface PackageMap { 198 | [packageId: string]: Package; 199 | } 200 | 201 | interface PathMap extends MapReplacement {} 202 | 203 | interface ModuleShim { 204 | deps?: string[]; 205 | exports?: string; 206 | init?: (...dependencies: any[]) => any; 207 | } 208 | 209 | interface Require { 210 | (dependencies: string[], callback: RequireCallback): void; 211 | (moduleId: string): ModuleType; 212 | 213 | toAbsMid(moduleId: string): string; 214 | toUrl(path: string): string; 215 | } 216 | 217 | interface RequireCallback { 218 | (...modules: any[]): void; 219 | } 220 | 221 | interface RootRequire extends Require { 222 | cache(cache: DojoLoader.ObjectMap): void; 223 | has: Has; 224 | on(type: SignalType, listener: any): { remove: () => void }; 225 | config(config: Config): void; 226 | inspect?(name: string): any; 227 | nodeRequire?(id: string): any; 228 | undef(moduleId: string, recursive?: boolean): void; 229 | } 230 | 231 | type SignalType = 'error'; 232 | } 233 | 234 | declare const define: DojoLoader.Define; 235 | 236 | declare interface NodeRequire { 237 | (dependencies: string[], callback: DojoLoader.RequireCallback): void; 238 | 239 | config(config: DojoLoader.Config): void; 240 | has: DojoLoader.Has; 241 | inspect?(name: string): any; 242 | nodeRequire?: NodeRequire; 243 | on(type: DojoLoader.SignalType, listener: any): { remove: () => void }; 244 | toAbsMid(moduleId: string): string; 245 | toUrl(path: string): string; 246 | undef(moduleId: string, recursive?: boolean): void; 247 | } 248 | 249 | declare var arguments: IArguments; 250 | -------------------------------------------------------------------------------- /src/loader.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import ModuleShim = DojoLoader.ModuleShim; 3 | import Module = DojoLoader.Module; 4 | import Package = DojoLoader.Package; 5 | 6 | // Nashorn global 7 | declare var Packages: { [key: string]: any; } | undefined; 8 | 9 | (function(args?: string[]): void { 10 | let globalObject: any = (function(): any { 11 | if (typeof window !== 'undefined') { 12 | // Browsers 13 | return window; 14 | } else if (typeof global !== 'undefined') { 15 | // Node 16 | return global; 17 | } else if (typeof self !== 'undefined') { 18 | // Web workers 19 | return self; 20 | } 21 | return {}; 22 | })(); 23 | 24 | // Nashorn global 25 | const load: (module: string) => any = globalObject.load; 26 | 27 | // webworker global 28 | const importScripts: ((url: string) => void) = globalObject.importScripts; 29 | 30 | const EXECUTING = 'executing'; 31 | const ABORT_EXECUTION: Object = {}; 32 | // 33 | // loader state data 34 | // 35 | 36 | // hash: (mid | url)-->(function | string) 37 | // 38 | // A cache of resources. The resources arrive via a require.cache application, which takes a hash from either 39 | // mid --> function or url --> string. The function associated with mid keys causes the same code to execute as if 40 | // the module was script injected. 41 | // 42 | // Both kinds of key-value pairs are entered into cache via the function consumePendingCache, which may relocate 43 | // keys as given by any mappings *iff* the cache was received as part of a module resource request. 44 | let cache: DojoLoader.ObjectMap = {}; 45 | 46 | let checkCompleteGuard = 0; 47 | 48 | // The configuration passed to the loader 49 | let config: DojoLoader.Config = { 50 | baseUrl: './', 51 | packages: [], 52 | paths: {}, 53 | pkgs: {}, 54 | shim: {}, 55 | crossOrigin: false 56 | }; 57 | 58 | // The arguments sent to loader via AMD define(). 59 | let moduleDefinitionArguments: DojoLoader.ModuleDefinitionArguments | undefined = undefined; 60 | 61 | // The list of modules that need to be evaluated. 62 | let executionQueue: DojoLoader.Module[] = []; 63 | 64 | let executedSomething = false; 65 | 66 | let injectUrl: ( 67 | url: string, 68 | callback: (node?: HTMLScriptElement) => void, 69 | module: DojoLoader.Module, 70 | parent?: DojoLoader.Module 71 | ) => void; 72 | 73 | // array of quads as described by computeMapProg; map-key is AMD map key, map-value is AMD map value 74 | let mapPrograms: DojoLoader.MapRoot = []; 75 | 76 | // A hash: (mid) --> (module-object) the module namespace 77 | // 78 | // pid: the package identifier to which the module belongs (e.g., "dojo"); "" indicates the system or default 79 | // package 80 | // mid: the fully-resolved (i.e., mappings have been applied) module identifier without the package identifier 81 | // (e.g., "dojo/io/script") 82 | // url: the URL from which the module was retrieved 83 | // pack: the package object of the package to which the module belongs 84 | // executed: false => not executed; EXECUTING => in the process of tranversing deps and running factory; 85 | // true => factory has been executed 86 | // deps: the dependency array for this module (array of modules objects) 87 | // def: the factory for this module 88 | // result: the result of the running the factory for this module 89 | // injected: true => module has been injected 90 | // load, normalize: plugin functions applicable only for plugins 91 | // 92 | // Modules go through several phases in creation: 93 | // 94 | // 1. Requested: some other module's definition or a require application contained the requested module in 95 | // its dependency array 96 | // 97 | // 2. Injected: a script element has been appended to the insert-point element demanding the resource implied by 98 | // the URL 99 | // 100 | // 3. Loaded: the resource injected in [2] has been evaluated. 101 | // 102 | // 4. Defined: the resource contained a define statement that advised the loader about the module. 103 | // 104 | // 5. Evaluated: the module was defined via define and the loader has evaluated the factory and computed a result. 105 | let modules: { [moduleId: string]: DojoLoader.Module | undefined } = {}; 106 | 107 | // list of (from-path, to-path, regex, length) derived from paths; 108 | // a "program" to apply paths; see computeMapProg 109 | let pathMapPrograms: DojoLoader.PathMap[] = []; 110 | 111 | let setGlobals: (require: DojoLoader.RootRequire, define: DojoLoader.Define) => void; 112 | 113 | let uidGenerator = 0; 114 | 115 | // the number of modules the loader has injected but has not seen defined 116 | let waitingCount = 0; 117 | 118 | const has: DojoLoader.Has = (function(): DojoLoader.Has { 119 | const hasCache: { [name: string]: any } = Object.create(null); 120 | const global: Window = globalObject; 121 | const document: HTMLDocument = global.document; 122 | const element: HTMLDivElement = document && document.createElement('div'); 123 | 124 | const has: DojoLoader.Has = function(name: string): any { 125 | return typeof hasCache[name] === 'function' 126 | ? (hasCache[name] = hasCache[name](global, document, element)) 127 | : hasCache[name]; 128 | }; 129 | 130 | has.add = function(name: string, test: any, now: boolean, force: boolean): void { 131 | (!(name in hasCache) || force) && (hasCache[name] = test); 132 | now && has(name); 133 | }; 134 | 135 | return has; 136 | })(); 137 | 138 | const requireModule: DojoLoader.RootRequire = function( 139 | dependencies: any, 140 | callback?: DojoLoader.RequireCallback 141 | ): DojoLoader.Module { 142 | return contextRequire(dependencies, callback); 143 | }; 144 | 145 | const listenerQueues: { [queue: string]: ((...args: any[]) => void)[] } = {}; 146 | 147 | const emit = function(type: DojoLoader.SignalType, args: {}): number | boolean { 148 | let queue = listenerQueues[type]; 149 | let hasListeners = queue && queue.length; 150 | 151 | if (hasListeners) { 152 | for (let listener of queue.slice(0)) { 153 | listener.apply(null, Array.isArray(args) ? args : [args]); 154 | } 155 | } 156 | 157 | return hasListeners; 158 | }; 159 | 160 | const reportModuleLoadError = function( 161 | parent: DojoLoader.Module | undefined, 162 | module: DojoLoader.Module, 163 | url: string, 164 | details?: string 165 | ): void { 166 | const parentMid = parent ? ` (parent: ${parent.mid})` : ''; 167 | const message = `Failed to load module ${module.mid} from ${url}${parentMid}`; 168 | const error = mix(new Error(message), { 169 | src: 'dojo/loader', 170 | info: { 171 | module, 172 | url, 173 | parentMid, 174 | details 175 | } 176 | }); 177 | 178 | if (!emit('error', error)) { 179 | throw error; 180 | } 181 | }; 182 | 183 | const on = function(type: string, listener: (error: DojoLoader.LoaderError) => void): { remove: () => void } { 184 | let queue = listenerQueues[type] || (listenerQueues[type] = []); 185 | 186 | queue.push(listener); 187 | 188 | return { 189 | remove(): void { 190 | queue.splice(queue.indexOf(listener), 1); 191 | } 192 | }; 193 | }; 194 | 195 | requireModule.has = has; 196 | requireModule.on = on; 197 | 198 | has.add('host-browser', typeof document !== 'undefined' && typeof location !== 'undefined'); 199 | has.add('host-node', typeof process === 'object' && process.versions && process.versions.node); 200 | has.add('host-nashorn', typeof load === 'function' && typeof Packages !== 'undefined'); 201 | has.add('host-web-worker', !has('host-browser') && typeof importScripts !== 'undefined'); 202 | has.add('debug', true); 203 | 204 | has.add('loader-configurable', true); 205 | has.add('loader-config-attribute', true); 206 | if (has('loader-configurable')) { 207 | /** 208 | * Configures the loader. 209 | * 210 | * @param {{ ?baseUrl: string, ?map: Object, ?packages: Array.<({ name, ?location, ?main }|string)> }} config 211 | * The configuration data. 212 | */ 213 | requireModule.config = function(configuration: DojoLoader.Config): void { 214 | // Make sure baseUrl ends in a slash 215 | if (configuration.baseUrl) { 216 | configuration.baseUrl = configuration.baseUrl.replace(/\/*$/, '/'); 217 | } 218 | 219 | const mergeProps: DojoLoader.ObjectMap = { 220 | paths: true, 221 | bundles: true, 222 | config: true, 223 | map: true 224 | }; 225 | 226 | // Copy configuration over to config object 227 | for (let key in configuration) { 228 | const value = (configuration)[key]; 229 | if (mergeProps[key]) { 230 | if (!(config)[key]) { 231 | (config)[key] = {}; 232 | } 233 | mix((config)[key], value, true); 234 | } else { 235 | (config)[key] = value; 236 | } 237 | } 238 | 239 | // TODO: Expose all properties on req as getter/setters? Plugin modules like dojo/node being able to 240 | // retrieve baseUrl is important. baseUrl is defined as a getter currently. 241 | 242 | forEach(configuration.packages || [], function(packageDescriptor: DojoLoader.Package): void { 243 | // Allow shorthand package definition, where name and location are the same 244 | if (typeof packageDescriptor === 'string') { 245 | packageDescriptor = { name: packageDescriptor, location: packageDescriptor }; 246 | } 247 | 248 | if (packageDescriptor.location != null) { 249 | packageDescriptor.location = packageDescriptor.location.replace(/\/*$/, '/'); 250 | } 251 | 252 | if (config && config.pkgs && packageDescriptor.name) { 253 | config.pkgs[packageDescriptor.name] = packageDescriptor; 254 | } 255 | }); 256 | 257 | function computeMapProgram(map: DojoLoader.ModuleMapItem | undefined): DojoLoader.MapItem[] { 258 | // This method takes a map as represented by a JavaScript object and initializes an array of 259 | // arrays of (map-key, map-value, regex-for-map-key, length-of-map-key), sorted decreasing by length- 260 | // of-map-key. The regex looks for the map-key followed by either "/" or end-of-string at the beginning 261 | // of a the search source. 262 | // 263 | // Maps look like this: 264 | // 265 | // map: { C: { D: E } } 266 | // A B 267 | // 268 | // The computed mapping is a 4-array deep tree, where the outermost array corresponds to the source 269 | // mapping object A, the 2nd level arrays each correspond to one of the source mappings C -> B, the 3rd 270 | // level arrays correspond to each destination mapping object B, and the innermost arrays each 271 | // correspond to one of the destination mappings D -> E. 272 | // 273 | // So, the overall structure looks like this: 274 | // 275 | // mapPrograms = [ source mapping array, source mapping array, ... ] 276 | // source mapping array = [ 277 | // source module id, 278 | // [ destination mapping array, destination mapping array, ... ], 279 | // RegExp that matches on source module id, 280 | // source module id length 281 | // ] 282 | // destination mapping array = [ 283 | // original module id, 284 | // destination module id, 285 | // RegExp that matches on original module id, 286 | // original module id length 287 | // ] 288 | 289 | const result: DojoLoader.MapItem[] = []; 290 | 291 | if (map) { 292 | for (let moduleId in map) { 293 | const value: any = (map)[moduleId]; 294 | const isValueAMapReplacement: boolean = typeof value === 'object'; 295 | 296 | const item = { 297 | 0: moduleId, 298 | 1: isValueAMapReplacement ? computeMapProgram(value) : value, 299 | 2: new RegExp('^' + moduleId.replace(/[-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&') + '(?:/|$)'), 300 | 3: moduleId.length 301 | }; 302 | result.push(item); 303 | 304 | if (isValueAMapReplacement && moduleId === '*') { 305 | (result).star = item[1]; 306 | } 307 | } 308 | } 309 | 310 | result.sort(function(left: DojoLoader.MapItem, right: DojoLoader.MapItem): number { 311 | return right[3] - left[3]; 312 | }); 313 | 314 | return result; 315 | } 316 | 317 | // FIXME this is a down-cast. 318 | // computeMapProgram => MapItem[] => mapPrograms: MapSource[] 319 | // MapSource[1] => MapReplacement[] is more specific than MapItems[1] => any 320 | mapPrograms = computeMapProgram(config.map); 321 | 322 | // Note that old paths will get destroyed if reconfigured 323 | configuration.paths && (pathMapPrograms = computeMapProgram(configuration.paths)); 324 | 325 | // shim API 326 | if (config.shim) { 327 | Object.keys(config.shim).forEach((moduleId) => { 328 | // guards currently get reset in callbacks: https://github.com/Microsoft/TypeScript/issues/11498 329 | const value = config.shim![moduleId]; 330 | let moduleDef: ModuleShim; 331 | 332 | // using shorthand module syntax, convert to full syntax 333 | if (Array.isArray(value)) { 334 | moduleDef = { 335 | deps: value 336 | }; 337 | } else { 338 | moduleDef = value; 339 | } 340 | 341 | define(moduleId, moduleDef.deps || [], function(...dependencies) { 342 | let root: any; 343 | 344 | let globalPath = moduleDef.exports; 345 | 346 | if (globalPath) { 347 | root = globalObject; 348 | 349 | globalPath.split('.').forEach((pathComponent) => { 350 | if (!(pathComponent in root)) { 351 | throw new Error(`Tried to find ${globalPath} but it did not exist`); 352 | } else { 353 | root = root[pathComponent]; 354 | } 355 | }); 356 | } 357 | 358 | if (moduleDef.init) { 359 | let newReturnValue: any = moduleDef.init(...dependencies); 360 | 361 | if (newReturnValue !== undefined) { 362 | root = newReturnValue; 363 | } 364 | } 365 | 366 | return root; 367 | }); 368 | }); 369 | } 370 | }; 371 | 372 | if (has('loader-config-attribute') && has('host-browser')) { 373 | Array.prototype.slice 374 | .call(document.getElementsByTagName('script'), 0) 375 | .forEach((script: HTMLScriptElement) => { 376 | if (script.hasAttribute('data-loader-config')) { 377 | const attr = script.getAttribute('data-loader-config'); 378 | let dojoConfig: DojoLoader.Config | null = null; 379 | 380 | try { 381 | dojoConfig = JSON.parse(`{ ${attr} }`); 382 | } catch (e) { 383 | console.error('Unable to parse data-loader-config, ' + attr); 384 | console.error(e); 385 | } 386 | 387 | if (dojoConfig !== null) { 388 | requireModule.config(dojoConfig); 389 | } 390 | } 391 | }); 392 | } 393 | } 394 | 395 | function forEach(array: T[], callback: (value: T, index: number, array: T[]) => void): void { 396 | array && array.forEach(callback); 397 | } 398 | 399 | function mix(target: {}, source: {}, deep?: boolean): T { 400 | if (source) { 401 | for (let key in source) { 402 | let sourceValue = (source)[key]; 403 | 404 | if ( 405 | deep && 406 | typeof sourceValue === 'object' && 407 | !Array.isArray(sourceValue) && 408 | !(sourceValue instanceof RegExp) 409 | ) { 410 | if (!(target)[key]) { 411 | (target)[key] = {}; 412 | } 413 | mix((target)[key], sourceValue, true); 414 | } else { 415 | (target)[key] = sourceValue; 416 | } 417 | } 418 | } 419 | return target; 420 | } 421 | 422 | function noop(): void {} 423 | 424 | let loadNodeModule: (moduleId: string, parent?: DojoLoader.Module) => any = noop; 425 | 426 | function contextRequire(moduleId: string, unused?: void, referenceModule?: DojoLoader.Module): DojoLoader.Module; 427 | function contextRequire( 428 | dependencies: string[], 429 | callback?: DojoLoader.RequireCallback, 430 | referenceModule?: DojoLoader.Module 431 | ): DojoLoader.Module; 432 | function contextRequire( 433 | dependencies: string | string[], 434 | callback: any, 435 | referenceModule?: DojoLoader.Module 436 | ): DojoLoader.Module | undefined { 437 | let module: DojoLoader.Module | undefined = undefined; 438 | if (typeof dependencies === 'string') { 439 | module = getModule(dependencies, referenceModule); 440 | if (module.executed !== true && module.executed !== EXECUTING) { 441 | if (has('host-node') && !module.plugin) { 442 | try { 443 | let result = loadNodeModule(module.mid, referenceModule); 444 | 445 | initializeModule(module, [], undefined); 446 | module.result = result; 447 | module.cjs.setExports(result); 448 | module.executed = true; 449 | module.injected = true; 450 | } catch (error) { 451 | throw new Error('Attempt to require unloaded module ' + module.mid); 452 | } 453 | } else if (module.plugin) { 454 | injectModule(module, undefined); 455 | } 456 | } 457 | // Assign the result of the module to `module` 458 | // otherwise require('moduleId') returns the internal 459 | // module representation 460 | module = module.result; 461 | } else if (Array.isArray(dependencies)) { 462 | // signature is (requestList [,callback]) 463 | // construct a synthetic module to control execution of the requestList, and, optionally, callback 464 | module = getModuleInformation('*' + ++uidGenerator); 465 | mix(module, { 466 | deps: resolveDependencies(dependencies, module, referenceModule), 467 | def: callback || {}, 468 | gc: true // garbage collect 469 | }); 470 | guardCheckComplete(function(): void { 471 | forEach(module ? module.deps : [], injectModule.bind(null, module)); 472 | }); 473 | executionQueue.push(module); 474 | checkComplete(); 475 | } 476 | return module; 477 | } 478 | 479 | function createRequire(module: DojoLoader.Module | undefined): DojoLoader.Require | undefined { 480 | let result: DojoLoader.Require | undefined = (!module && requireModule) || (module && module.require); 481 | if (!result && module) { 482 | module.require = result = function( 483 | dependencies: any, 484 | callback: any 485 | ): DojoLoader.Module { 486 | return contextRequire(dependencies, callback, module); 487 | }; 488 | mix(mix(result, requireModule), { 489 | toUrl: function(name: string): string { 490 | return toUrl(name, module); 491 | }, 492 | toAbsMid: function(mid: string): string { 493 | return toAbsMid(mid, module); 494 | } 495 | }); 496 | } 497 | return result; 498 | } 499 | 500 | function runMapProgram(targetModuleId: string, map?: DojoLoader.MapItem[]): DojoLoader.MapSource | undefined { 501 | // search for targetModuleId in map; return the map item if found; falsy otherwise 502 | if (map) { 503 | for (let i = 0, j = map.length; i < j; ++i) { 504 | if (map[i][2].test(targetModuleId)) { 505 | return map[i]; 506 | } 507 | } 508 | } 509 | 510 | return undefined; 511 | } 512 | 513 | function compactPath(path: string): string { 514 | const pathSegments: string[] = path.replace(/\\/g, '/').split('/'); 515 | let absolutePathSegments: (string | undefined)[] = []; 516 | let segment: string | undefined; 517 | let lastSegment: string | undefined = ''; 518 | 519 | while (pathSegments.length) { 520 | segment = pathSegments.shift(); 521 | if (segment === '..' && absolutePathSegments.length && lastSegment !== '..') { 522 | absolutePathSegments.pop(); 523 | lastSegment = absolutePathSegments[absolutePathSegments.length - 1]; 524 | } else if (segment !== '.') { 525 | absolutePathSegments.push((lastSegment = segment)); 526 | } // else ignore "." 527 | } 528 | 529 | return absolutePathSegments.join('/'); 530 | } 531 | 532 | function updateModuleIdFromMap(moduleId: string, referenceModule?: DojoLoader.Module): string { 533 | // relative module ids are relative to the referenceModule; get rid of any dots 534 | moduleId = compactPath( 535 | /^\./.test(moduleId) && referenceModule ? referenceModule.mid + '/../' + moduleId : moduleId 536 | ); 537 | // at this point, moduleId is an absolute moduleId 538 | 539 | // if there is a reference module, then use its module map, if one exists; otherwise, use the global map. 540 | // see computeMapProg for more information on the structure of the map arrays 541 | let moduleMap: DojoLoader.MapItem | undefined = 542 | referenceModule && runMapProgram(referenceModule.mid, mapPrograms); 543 | moduleMap = moduleMap ? moduleMap[1] : mapPrograms.star; 544 | 545 | let mapItem: DojoLoader.MapItem | undefined; 546 | if ((mapItem = runMapProgram(moduleId, moduleMap))) { 547 | moduleId = mapItem[1] + moduleId.slice(mapItem[3]); 548 | } 549 | 550 | return moduleId; 551 | } 552 | 553 | function getPluginInformation( 554 | moduleId: string, 555 | match: string[], 556 | referenceModule?: DojoLoader.Module 557 | ): DojoLoader.Module { 558 | const plugin = getModule(match[1], referenceModule); 559 | const isPluginLoaded = Boolean(plugin.load); 560 | 561 | const contextRequire = createRequire(referenceModule); 562 | 563 | let pluginResourceId: string; 564 | if (isPluginLoaded) { 565 | pluginResourceId = resolvePluginResourceId(plugin, match[2], contextRequire); 566 | moduleId = plugin.mid + '!' + pluginResourceId; 567 | } else { 568 | // if not loaded, need to mark in a way that it will get properly resolved later 569 | pluginResourceId = match[2]; 570 | moduleId = plugin.mid + '!' + ++uidGenerator + '!*'; 571 | } 572 | return ({ 573 | plugin: plugin, 574 | mid: moduleId, 575 | req: contextRequire, 576 | prid: pluginResourceId, 577 | fix: !isPluginLoaded 578 | }); 579 | } 580 | 581 | function getModuleInformation(moduleId: string, referenceModule?: DojoLoader.Module): DojoLoader.Module { 582 | let packageId = ''; 583 | let pack: Package = {}; 584 | let moduleIdInPackage = ''; 585 | 586 | const matches = Object.keys((config && config.pkgs) || {}) 587 | .filter((pkg) => (moduleId + '/').indexOf(pkg + '/') === 0) 588 | .sort((a, b) => (a.length > b.length ? -1 : 1)); 589 | 590 | if (matches.length) { 591 | packageId = matches.shift() as string; 592 | pack = config.pkgs![packageId]; 593 | moduleId = 594 | packageId + '/' + (moduleIdInPackage = moduleId.substr(packageId.length + 1) || pack.main || 'main'); 595 | } 596 | 597 | let module = modules[moduleId]; 598 | if (!module) { 599 | let mapItem = runMapProgram(moduleId, pathMapPrograms); 600 | let url = mapItem 601 | ? mapItem[1] + moduleId.slice(mapItem[3]) 602 | : packageId ? pack.location + moduleIdInPackage : moduleId; 603 | module = ({ 604 | pid: packageId, 605 | mid: moduleId, 606 | pack: pack, 607 | url: compactPath( 608 | // absolute urls should not be prefixed with baseUrl 609 | (/^(?:\/|\w+:)/.test(url) ? '' : config.baseUrl) + 610 | url + 611 | // urls with a javascript extension should not have another one added 612 | (/\.js(?:\?[^?]*)?$/.test(url) ? '' : '.js') 613 | ) 614 | }); 615 | } 616 | 617 | return module; 618 | } 619 | 620 | function resolvePluginResourceId( 621 | plugin: DojoLoader.Module, 622 | pluginResourceId: string, 623 | contextRequire?: DojoLoader.Require 624 | ): string { 625 | const toAbsMid = contextRequire ? contextRequire.toAbsMid : undefined; 626 | return plugin.normalize 627 | ? plugin.normalize(pluginResourceId, toAbsMid) 628 | : toAbsMid ? toAbsMid(pluginResourceId) : ''; 629 | } 630 | 631 | function getModule(moduleId: string, referenceModule?: DojoLoader.Module): DojoLoader.Module { 632 | // compute and construct (if necessary) the module implied by the moduleId with respect to referenceModule 633 | let module: DojoLoader.Module; 634 | const pluginRegEx = /^(.+?)\!(.*)$/; 635 | 636 | // Foreseable situations (where ?-> is a map lookup function) 637 | // module 638 | // plugin!arg 639 | // module ?-> mappedModule 640 | // module ?-> mappedPlugin!arg 641 | // plugin!arg ?-> mappedPlugin + ! + arg 642 | 643 | // Do inital check on the passed in moduleId 644 | const passedModuleMatch = moduleId.match(pluginRegEx); 645 | if (passedModuleMatch) { 646 | // Passed in moduleId is a plugin, so check the map using only the plugin name 647 | // then reconstruct using the pluginArgs 648 | let pluginId: string = updateModuleIdFromMap(passedModuleMatch[1], referenceModule); 649 | moduleId = `${pluginId}!${passedModuleMatch[2]}`; 650 | } else { 651 | // Not a module, so check the map using the full moduleId passed 652 | moduleId = updateModuleIdFromMap(moduleId, referenceModule); 653 | } 654 | 655 | // Do final check on the mapped module / plugin Id to see what we're dealing with 656 | const mappedModuleMatch = moduleId.match(pluginRegEx); 657 | if (mappedModuleMatch) { 658 | module = getPluginInformation(moduleId, mappedModuleMatch, referenceModule); 659 | } else { 660 | module = getModuleInformation(moduleId, referenceModule); 661 | } 662 | 663 | return modules[module.mid] || (modules[module.mid] = module); 664 | } 665 | 666 | function toAbsMid(moduleId: string, referenceModule: DojoLoader.Module | undefined): string { 667 | moduleId = updateModuleIdFromMap(moduleId, referenceModule); 668 | return getModuleInformation(moduleId, referenceModule).mid; 669 | } 670 | 671 | function toUrl(name: string, referenceModule: DojoLoader.Module | undefined): string { 672 | let moduleId = name + '/x'; 673 | moduleId = updateModuleIdFromMap(moduleId, referenceModule); 674 | const moduleInfo: DojoLoader.Module = getModuleInformation(moduleId, referenceModule); 675 | const url: string = moduleInfo.url; 676 | 677 | // "/x.js" since getModuleInfo automatically appends ".js" and we appended "/x" to make name look like a 678 | // module id 679 | return url.slice(0, url.length - 5); 680 | } 681 | 682 | function makeCommonJs(mid: string): DojoLoader.Module { 683 | return (modules[mid] = ({ 684 | mid: mid, 685 | injected: true, 686 | executed: true 687 | })); 688 | } 689 | const commonJsRequireModule: DojoLoader.Module = makeCommonJs('require'); 690 | const commonJsExportsModule: DojoLoader.Module = makeCommonJs('exports'); 691 | const commonJsModuleModule: DojoLoader.Module = makeCommonJs('module'); 692 | let circularTrace: string[]; 693 | 694 | has.add('loader-debug-circular-dependencies', true); 695 | if (has('loader-debug-circular-dependencies')) { 696 | circularTrace = []; 697 | } 698 | 699 | function executeModule(module: DojoLoader.Module): any { 700 | // run the dependency array, then run the factory for module 701 | if (module.executed === EXECUTING) { 702 | // for circular dependencies, assume the first module encountered was executed OK 703 | // modules that circularly depend on a module that has not run its factory will get 704 | // the premade cjs.exports===module.result. They can take a reference to this object and/or 705 | // add properties to it. When the module finally runs its factory, the factory can 706 | // read/write/replace this object. Notice that so long as the object isn't replaced, any 707 | // reference taken earlier while walking the dependencies list is still valid. 708 | if ( 709 | has('loader-debug-circular-dependencies') && 710 | module.deps.indexOf(commonJsExportsModule) === -1 && 711 | typeof console !== 'undefined' 712 | ) { 713 | console.warn('Circular dependency: ' + circularTrace.concat(module.mid).join(' -> ')); 714 | } 715 | 716 | return module.result; 717 | } 718 | 719 | if (!module.executed) { 720 | // TODO: This seems like an incorrect condition inference. Originally it was simply !module.def 721 | // which caused modules with falsy defined values to never execute. 722 | if (!module.def && !module.deps) { 723 | return ABORT_EXECUTION; 724 | } 725 | 726 | has('loader-debug-circular-dependencies') && circularTrace.push(module.mid); 727 | 728 | const dependencies: DojoLoader.Module[] = module.deps; 729 | let result: any; 730 | 731 | module.executed = EXECUTING; 732 | let executedDependencies = dependencies.map(function(dependency: DojoLoader.Module): any { 733 | if (result !== ABORT_EXECUTION) { 734 | // check for keyword dependencies: DojoLoader.require, exports, module; then execute module dependency 735 | result = 736 | dependency === commonJsRequireModule 737 | ? createRequire(module) 738 | : dependency === commonJsExportsModule 739 | ? module.cjs.exports 740 | : dependency === commonJsModuleModule ? module.cjs : executeModule(dependency); 741 | } 742 | return result; 743 | }); 744 | 745 | if (result === ABORT_EXECUTION) { 746 | module.executed = false; 747 | has('loader-debug-circular-dependencies') && circularTrace.pop(); 748 | return ABORT_EXECUTION; 749 | } 750 | 751 | const factory: DojoLoader.Factory = module.def; 752 | result = typeof factory === 'function' ? factory.apply(null, executedDependencies) : factory; 753 | 754 | // TODO: But of course, module.cjs always exists. 755 | // Assign the new module.result to result so plugins can use exports 756 | // to define their interface; the plugin checks below use result 757 | result = module.result = result === undefined && module.cjs ? module.cjs.exports : result; 758 | module.executed = true; 759 | executedSomething = true; 760 | 761 | // delete references to synthetic modules 762 | if (module.gc) { 763 | modules[module.mid] = undefined; 764 | } 765 | 766 | // if result defines load, just assume it's a plugin; harmless if the assumption is wrong 767 | result && 768 | result.load && 769 | ['normalize', 'load'].forEach(function(key: string): void { 770 | (module)[key] = (result)[key]; 771 | }); 772 | 773 | // for plugins, resolve the loadQ 774 | forEach(module.loadQ || [], function(pseudoPluginResource: DojoLoader.Module): void { 775 | // manufacture and insert the real module in modules 776 | const pluginResourceId: string = resolvePluginResourceId( 777 | module, 778 | pseudoPluginResource.prid, 779 | pseudoPluginResource.req 780 | ); 781 | const moduleId: string = module.mid + '!' + pluginResourceId; 782 | const pluginResource: DojoLoader.Module = mix(mix({}, pseudoPluginResource), { 783 | mid: moduleId, 784 | prid: pluginResourceId 785 | }); 786 | 787 | if (!modules[moduleId]) { 788 | // create a new (the real) plugin resource and inject it normally now that the plugin is on board 789 | injectPlugin((modules[moduleId] = pluginResource)); 790 | } // else this was a duplicate request for the same (plugin, rid) 791 | 792 | // pluginResource is really just a placeholder with the wrong moduleId (because we couldn't calculate it 793 | // until the plugin was on board) fix() replaces the pseudo module in a resolved dependencies array with the 794 | // real module lastly, mark the pseudo module as arrived and delete it from modules 795 | if (pseudoPluginResource && pseudoPluginResource.fix) { 796 | pseudoPluginResource.fix(modules[moduleId]); 797 | } 798 | --waitingCount; 799 | modules[pseudoPluginResource.mid] = undefined; 800 | }); 801 | module.loadQ = undefined; 802 | 803 | has('loader-debug-circular-dependencies') && circularTrace.pop(); 804 | } 805 | 806 | // at this point the module is guaranteed fully executed 807 | return module.result; 808 | } 809 | 810 | // TODO: Figure out what proc actually is 811 | function guardCheckComplete(callback: Function): void { 812 | ++checkCompleteGuard; 813 | callback(); 814 | --checkCompleteGuard; 815 | } 816 | 817 | function checkComplete(): void { 818 | // keep going through the executionQueue as long as at least one factory is executed 819 | // plugins, recursion, cached modules all make for many execution path possibilities 820 | !checkCompleteGuard && 821 | guardCheckComplete(function(): void { 822 | for (let module: DojoLoader.Module, i = 0; i < executionQueue.length; ) { 823 | module = executionQueue[i]; 824 | if (module.executed === true) { 825 | executionQueue.splice(i, 1); 826 | } else { 827 | executedSomething = false; 828 | executeModule(module); 829 | if (executedSomething) { 830 | // something was executed; this indicates the executionQueue was modified, maybe a 831 | // lot (for example a later module causes an earlier module to execute) 832 | i = 0; 833 | } else { 834 | // nothing happened; check the next module in the exec queue 835 | i++; 836 | } 837 | } 838 | } 839 | }); 840 | } 841 | 842 | function injectPlugin(module: DojoLoader.Module): void { 843 | // injects the plugin module given by module; may have to inject the plugin itself 844 | const plugin: DojoLoader.Module | undefined = module.plugin; 845 | const onLoad = function(def: any): void { 846 | module.result = def; 847 | --waitingCount; 848 | module.executed = true; 849 | checkComplete(); 850 | }; 851 | 852 | if (plugin && plugin.load) { 853 | plugin.load(module.prid, module.req, onLoad, config); 854 | } else if (plugin && plugin.loadQ) { 855 | plugin.loadQ.push(module); 856 | } else if (plugin) { 857 | // the unshift instead of push is important: we don't want plugins to execute as 858 | // dependencies of some other module because this may cause circles when the plugin 859 | // loadQ is run; also, generally, we want plugins to run early since they may load 860 | // several other modules and therefore can potentially unblock many modules 861 | plugin.loadQ = [module]; 862 | executionQueue.unshift(plugin); 863 | injectModule(module, plugin); 864 | } 865 | } 866 | 867 | function injectModule(parent?: DojoLoader.Module, module?: DojoLoader.Module): void { 868 | // TODO: This is for debugging, we should bracket it 869 | if (!module) { 870 | module = parent; 871 | parent = undefined; 872 | } 873 | 874 | if (module && module.plugin) { 875 | injectPlugin(module); 876 | } else if (module && !module.injected) { 877 | let cached: DojoLoader.Factory; 878 | const onLoadCallback = function(node?: HTMLScriptElement): void { 879 | let moduleDefArgs: string[] = []; 880 | let moduleDefFactory: DojoLoader.Factory | undefined = undefined; 881 | 882 | // non-amd module 883 | if (moduleDefinitionArguments) { 884 | moduleDefArgs = moduleDefinitionArguments[0]; 885 | moduleDefFactory = moduleDefinitionArguments[1]; 886 | } 887 | 888 | defineModule(module, moduleDefArgs, moduleDefFactory); 889 | moduleDefinitionArguments = undefined; 890 | 891 | guardCheckComplete(function(): void { 892 | forEach((module && module.deps) || [], injectModule.bind(null, module)); 893 | }); 894 | checkComplete(); 895 | }; 896 | 897 | ++waitingCount; 898 | module.injected = true; 899 | if ((cached = cache[module.mid])) { 900 | try { 901 | cached(); 902 | onLoadCallback(); 903 | return; 904 | } catch (error) { 905 | // If a cache load fails, retrieve using injectUrl 906 | // TODO: report error, 'cachedThrew', [ error, module ] 907 | } 908 | } 909 | injectUrl(module.url, onLoadCallback, module, parent); 910 | } 911 | } 912 | 913 | function resolveDependencies( 914 | dependencies: string[], 915 | module: DojoLoader.Module, 916 | referenceModule?: DojoLoader.Module 917 | ): DojoLoader.Module[] { 918 | // resolve dependencies with respect to this module 919 | return dependencies.map(function(dependency: string, i: number): DojoLoader.Module { 920 | const result: DojoLoader.Module = getModule(dependency, referenceModule); 921 | if (result.fix) { 922 | result.fix = function(m: DojoLoader.Module): void { 923 | module.deps[i] = m; 924 | }; 925 | } 926 | return result; 927 | }); 928 | } 929 | 930 | function defineModule( 931 | module: DojoLoader.Module | undefined, 932 | dependencies: string[], 933 | factory?: DojoLoader.Factory 934 | ): DojoLoader.Module | undefined { 935 | --waitingCount; 936 | return initializeModule(module, dependencies, factory); 937 | } 938 | 939 | function initializeModule( 940 | module: DojoLoader.Module | undefined, 941 | dependencies: string[], 942 | factory?: DojoLoader.Factory 943 | ): DojoLoader.Module | undefined { 944 | const moduleToInitialize = module; 945 | let initializedModule: DojoLoader.Module | undefined = undefined; 946 | 947 | if (moduleToInitialize) { 948 | initializedModule = mix(moduleToInitialize, { 949 | def: factory, 950 | deps: resolveDependencies(dependencies, moduleToInitialize, moduleToInitialize), 951 | cjs: { 952 | id: moduleToInitialize.mid, 953 | uri: moduleToInitialize.url, 954 | exports: (moduleToInitialize.result = {}), 955 | setExports: function(exports: any): void { 956 | moduleToInitialize.cjs.exports = exports; 957 | } 958 | } 959 | }); 960 | } 961 | return initializedModule; 962 | } 963 | 964 | has.add('function-bind', Boolean(Function.prototype.bind)); 965 | if (!has('function-bind')) { 966 | injectModule.bind = function(thisArg: any): typeof injectModule { 967 | const slice = Array.prototype.slice; 968 | const args: any[] = slice.call(arguments, 1); 969 | 970 | return function(): void { 971 | return injectModule.apply(thisArg, args.concat(slice.call(arguments, 0))); 972 | }; 973 | }; 974 | } 975 | 976 | let globalObjectGlobals = function(require: DojoLoader.Require, define: DojoLoader.Define): void { 977 | globalObject.require = require; 978 | globalObject.define = define; 979 | }; 980 | 981 | if (has('host-node')) { 982 | loadNodeModule = (moduleId: string, parent?: DojoLoader.Module): any => { 983 | let module: any = require('module'); 984 | let result: any; 985 | 986 | if (module._findPath && module._nodeModulePaths) { 987 | let localModulePath = module._findPath(moduleId, module._nodeModulePaths(toUrl('.', parent))); 988 | 989 | if (localModulePath !== false) { 990 | moduleId = localModulePath; 991 | } 992 | } 993 | 994 | // Some modules attempt to detect an AMD loader by looking for global AMD `define`. This causes issues 995 | // when other CommonJS modules attempt to load them via the standard Node.js `require`, so hide it 996 | // during the load 997 | globalObject.define = undefined; 998 | 999 | try { 1000 | if (requireModule && requireModule.nodeRequire) { 1001 | result = requireModule.nodeRequire(moduleId); 1002 | } 1003 | } catch (error) { 1004 | throw error; 1005 | } finally { 1006 | globalObject.define = define; 1007 | } 1008 | 1009 | return result; 1010 | }; 1011 | 1012 | const vm: any = require('vm'); 1013 | const fs: any = require('fs'); 1014 | 1015 | // retain the ability to get node's require 1016 | requireModule.nodeRequire = require; 1017 | injectUrl = function( 1018 | url: string, 1019 | callback: (node?: HTMLScriptElement) => void, 1020 | module: DojoLoader.Module, 1021 | parent?: DojoLoader.Module 1022 | ): void { 1023 | fs.readFile(url, 'utf8', function(error: Error, data: string): void { 1024 | function loadCallback() { 1025 | try { 1026 | let result = loadNodeModule(module.mid, parent); 1027 | return result; 1028 | } catch (error) { 1029 | reportModuleLoadError(parent, module, url, error.message); 1030 | } 1031 | } 1032 | if (error) { 1033 | moduleDefinitionArguments = [[], loadCallback]; 1034 | } else { 1035 | // global `module` variable needs to be shadowed for UMD modules that are loaded in an Electron 1036 | // webview; in Node.js the `module` variable does not exist when using `vm.runInThisContext`, 1037 | // but in Electron it exists in the webview when Node.js integration is enabled which causes loaded 1038 | // modules to register with Node.js and break the loader 1039 | let oldModule = globalObject.module; 1040 | globalObject.module = undefined; 1041 | try { 1042 | /** 1043 | * Using an `object` as a second argument causes Instabul 1044 | * issues and then thinks the file should not be instrumented 1045 | * 1046 | * See: dojo/loader#57 1047 | */ 1048 | vm.runInThisContext(data, url); 1049 | } catch (error) { 1050 | reportModuleLoadError(parent, module, url, error.message); 1051 | } finally { 1052 | globalObject.module = oldModule; 1053 | } 1054 | } 1055 | 1056 | callback(); 1057 | }); 1058 | }; 1059 | 1060 | setGlobals = function(require: DojoLoader.RootRequire, define: DojoLoader.Define): void { 1061 | module.exports = globalObject.require = require; 1062 | globalObject.define = define; 1063 | }; 1064 | } else if (has('host-browser')) { 1065 | injectUrl = function( 1066 | url: string, 1067 | callback: (node?: HTMLScriptElement) => void, 1068 | module: DojoLoader.Module, 1069 | parent?: DojoLoader.Module 1070 | ): void { 1071 | // insert a script element to the insert-point element with src=url; 1072 | // apply callback upon detecting the script has loaded. 1073 | const node: HTMLScriptElement = document.createElement('script'); 1074 | const handler: EventListener = function(event: Event): void { 1075 | document.head.removeChild(node); 1076 | 1077 | if (event.type === 'load') { 1078 | callback(); 1079 | } else { 1080 | reportModuleLoadError(parent, module, url); 1081 | } 1082 | }; 1083 | 1084 | node.addEventListener('load', handler, false); 1085 | node.addEventListener('error', handler, false); 1086 | 1087 | if (config.crossOrigin !== false) { 1088 | (node).crossOrigin = config.crossOrigin; 1089 | } 1090 | 1091 | node.charset = 'utf-8'; 1092 | node.src = url; 1093 | document.head.appendChild(node); 1094 | }; 1095 | 1096 | setGlobals = globalObjectGlobals; 1097 | } else if (has('host-nashorn')) { 1098 | injectUrl = function( 1099 | url: string, 1100 | callback: (node?: HTMLScriptElement) => void, 1101 | module: DojoLoader.Module, 1102 | parent?: DojoLoader.Module 1103 | ): void { 1104 | load(url); 1105 | callback(); 1106 | }; 1107 | 1108 | setGlobals = globalObjectGlobals; 1109 | } else if (has('host-web-worker')) { 1110 | injectUrl = function( 1111 | url: string, 1112 | callback: (node?: HTMLScriptElement) => void, 1113 | module: DojoLoader.Module, 1114 | parent?: DojoLoader.Module 1115 | ): void { 1116 | try { 1117 | importScripts(url); 1118 | } catch (e) { 1119 | reportModuleLoadError(parent, module, url); 1120 | } 1121 | callback(); 1122 | }; 1123 | 1124 | setGlobals = globalObjectGlobals; 1125 | } else { 1126 | throw new Error('Unsupported platform'); 1127 | } 1128 | 1129 | has.add('loader-debug-internals', true); 1130 | if (has('loader-debug-internals')) { 1131 | requireModule.inspect = function(name: string): any { 1132 | /* tslint:disable:no-eval */ 1133 | // TODO: Should this use console.log so people do not get any bright ideas about using this in apps? 1134 | return eval(name); 1135 | /* tslint:enable:no-eval */ 1136 | }; 1137 | } 1138 | 1139 | has.add('loader-undef', true); 1140 | if (has('loader-undef')) { 1141 | requireModule.undef = function(id: string, recursive?: boolean): void { 1142 | const module: Module | undefined = modules[id]; 1143 | const undefDeps = function(mod: Module): void { 1144 | if (mod === commonJsRequireModule || mod === commonJsModuleModule || mod === commonJsExportsModule) { 1145 | return; 1146 | } 1147 | if (mod.deps) { 1148 | forEach(mod.deps, undefDeps); 1149 | } 1150 | 1151 | modules[mod.mid] = undefined; 1152 | }; 1153 | if (module) { 1154 | if (recursive && module.deps) { 1155 | forEach(module.deps, undefDeps); 1156 | } 1157 | delete modules[module.mid]; 1158 | delete cache[module.mid]; 1159 | } 1160 | }; 1161 | } 1162 | 1163 | mix(requireModule, { 1164 | toAbsMid: toAbsMid, 1165 | toUrl: toUrl, 1166 | 1167 | cache: function(cacheModules: DojoLoader.ObjectMap): void { 1168 | let item: any; 1169 | 1170 | for (let key in cacheModules) { 1171 | item = cacheModules[key]; 1172 | 1173 | cache[getModuleInformation(key, undefined).mid] = item; 1174 | } 1175 | } 1176 | }); 1177 | 1178 | Object.defineProperty(requireModule, 'baseUrl', { 1179 | get: function(): string | undefined { 1180 | return config.baseUrl; 1181 | }, 1182 | enumerable: true 1183 | }); 1184 | 1185 | has.add('loader-cjs-wrapping', true); 1186 | 1187 | let comments: RegExp; 1188 | let requireCall: RegExp; 1189 | 1190 | if (has('loader-cjs-wrapping')) { 1191 | comments = /\/\*[\s\S]*?\*\/|\/\/.*$/gm; 1192 | requireCall = /require\s*\(\s*(["'])(.*?[^\\])\1\s*\)/g; 1193 | } 1194 | 1195 | has.add('loader-explicit-mid', true); 1196 | 1197 | /** 1198 | * @param deps //(array of commonjs.moduleId, optional) 1199 | * @param factory //(any) 1200 | */ 1201 | let define: DojoLoader.Define = mix( 1202 | function(dependencies: string[], factory: DojoLoader.Factory): void { 1203 | let originalFactory: any; 1204 | if (has('loader-explicit-mid') && arguments.length > 1 && typeof dependencies === 'string') { 1205 | let id: string = dependencies; 1206 | if (arguments.length === 3) { 1207 | dependencies = factory; 1208 | factory = arguments[2]; 1209 | } else { 1210 | dependencies = []; 1211 | } 1212 | 1213 | // Some modules in the wild have an explicit module ID that is null; ignore the module ID in this case and 1214 | // register normally using the request module ID 1215 | if (id != null) { 1216 | let module: DojoLoader.Module = getModule(id); 1217 | if (factory) { 1218 | originalFactory = factory; 1219 | factory = function() { 1220 | module.executed = true; 1221 | return (module.result = originalFactory.apply 1222 | ? originalFactory.apply(null, arguments) 1223 | : originalFactory); 1224 | }; 1225 | } 1226 | module.injected = true; 1227 | defineModule(module, dependencies, factory); 1228 | guardCheckComplete(function(): void { 1229 | forEach(module.deps, injectModule.bind(null, module)); 1230 | }); 1231 | } 1232 | } 1233 | 1234 | if (arguments.length === 1) { 1235 | if (has('loader-cjs-wrapping') && typeof dependencies === 'function') { 1236 | originalFactory = dependencies; 1237 | dependencies = ['require', 'exports', 'module']; 1238 | 1239 | // Scan factory for require() calls and add them to the 1240 | // list of dependencies 1241 | originalFactory 1242 | .toString() 1243 | .replace(comments, '') 1244 | .replace(requireCall, function(): string { 1245 | dependencies.push(/* mid */ arguments[2]); 1246 | return arguments[0]; 1247 | }); 1248 | factory = function(require, exports, module): any { 1249 | const originalModuleId = module.id; 1250 | let result: any = originalFactory.apply(null, arguments); 1251 | if (originalModuleId !== module.id) { 1252 | const newModule: DojoLoader.Module = getModule(module.id); 1253 | defineModule(newModule, dependencies, undefined); 1254 | newModule.injected = true; 1255 | newModule.executed = true; 1256 | newModule.result = module.exports = result || module.exports; 1257 | } 1258 | return result; 1259 | }; 1260 | } else if (/* define(value) */ !Array.isArray(dependencies)) { 1261 | const value: any = dependencies; 1262 | dependencies = []; 1263 | factory = function(): any { 1264 | return value; 1265 | }; 1266 | } 1267 | } 1268 | 1269 | moduleDefinitionArguments = [dependencies, factory]; 1270 | }, 1271 | { 1272 | amd: { vendor: 'dojotoolkit.org' } 1273 | } 1274 | ); 1275 | 1276 | setGlobals(requireModule, define); 1277 | if (has('host-nashorn') && args && args[0]) { 1278 | load(args[0]); 1279 | } 1280 | })(typeof Packages !== 'undefined' ? Array.prototype.slice.call(arguments, 0) : []); 1281 | -------------------------------------------------------------------------------- /tests/common/a/app.js: -------------------------------------------------------------------------------- 1 | define([], 'app A'); 2 | -------------------------------------------------------------------------------- /tests/common/a/map2.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'mapped/app' 3 | ], function (app) { 4 | return { 5 | app: app 6 | }; 7 | }); 8 | -------------------------------------------------------------------------------- /tests/common/a/relative1.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './app' 3 | ], function (app) { 4 | return { 5 | app: app 6 | }; 7 | }); 8 | -------------------------------------------------------------------------------- /tests/common/a/remappedApp.js: -------------------------------------------------------------------------------- 1 | define([ 2 | '../app' 3 | ], function (app) { 4 | return 'remapped' + app; 5 | }); 6 | -------------------------------------------------------------------------------- /tests/common/amd/onlyFactory.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | return { 3 | property: 'value' 4 | }; 5 | }); 6 | -------------------------------------------------------------------------------- /tests/common/app.js: -------------------------------------------------------------------------------- 1 | define([], 'app'); 2 | -------------------------------------------------------------------------------- /tests/common/commonJs/Deep2.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | var deep3 = require('./deep3'); 3 | 4 | function Deep2() {} 5 | 6 | Deep2.prototype.deep3 = function () { 7 | return deep3(); 8 | }; 9 | 10 | module.exports = Deep2; 11 | }); 12 | -------------------------------------------------------------------------------- /tests/common/commonJs/app.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports) { 2 | exports.getMessage = function () { 3 | return 'Message from CommonJS app.'; 4 | }; 5 | }); 6 | -------------------------------------------------------------------------------- /tests/common/commonJs/app1.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | var testModule1 = require('test/module1'); 3 | 4 | exports.getMessage = function () { 5 | return testModule1; 6 | }; 7 | }); 8 | -------------------------------------------------------------------------------- /tests/common/commonJs/circular1.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports) { 2 | var circular2 = require('./circular2'); 3 | 4 | exports.getMessage = function () { 5 | return 'circular1'; 6 | }; 7 | 8 | exports.circular2Message = function () { 9 | return circular2.getMessage(); 10 | }; 11 | }); 12 | -------------------------------------------------------------------------------- /tests/common/commonJs/circular2.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports) { 2 | var circular1 = require('./circular1'); 3 | 4 | exports.getMessage = function () { 5 | return 'circular2'; 6 | }; 7 | 8 | exports.circular1Message = function() { 9 | return circular1.getMessage(); 10 | }; 11 | }); 12 | -------------------------------------------------------------------------------- /tests/common/commonJs/deep1.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | var Deep2 = require('./Deep2'); 3 | 4 | module.exports = function () { 5 | return new Deep2(); 6 | }; 7 | }); 8 | -------------------------------------------------------------------------------- /tests/common/commonJs/deep3.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | var deep4 = require('./deep4'); 3 | 4 | module.exports = function () { 5 | return deep4; 6 | }; 7 | }); 8 | -------------------------------------------------------------------------------- /tests/common/commonJs/deep4.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | module.exports = { 3 | objectExport: 'objectExport' 4 | }; 5 | }); 6 | -------------------------------------------------------------------------------- /tests/common/commonJs/testModule1.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | module.exports = 'testModule1'; 3 | module.id = 'test/module1'; 4 | }); 5 | -------------------------------------------------------------------------------- /tests/common/commonJs/testModule2.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | var testModule1 = require('test/module1'); 3 | 4 | module.exports = { 5 | testModule1Value: testModule1, 6 | testModule2Value: 'testModule2' 7 | }; 8 | 9 | module.id = 'test/module2'; 10 | }); 11 | -------------------------------------------------------------------------------- /tests/common/commonJs/testModule3.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | var app = require('./app'); 3 | 4 | module.exports = { 5 | appModuleValue: app.getMessage(), 6 | testModule3Value: 'testModule3' 7 | }; 8 | 9 | module.id = 'test/module3'; 10 | }); 11 | -------------------------------------------------------------------------------- /tests/common/map1.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'mapped/app' 3 | ], function (app) { 4 | return { 5 | app: app 6 | }; 7 | }); 8 | -------------------------------------------------------------------------------- /tests/common/plugin.js: -------------------------------------------------------------------------------- 1 | define({ 2 | load: function (name, require, loaded) { 3 | loaded(name); 4 | } 5 | }); 6 | -------------------------------------------------------------------------------- /tests/common/pluginConfig.js: -------------------------------------------------------------------------------- 1 | define({ 2 | load: function (name, require, loaded, config) { 3 | loaded(config); 4 | } 5 | }); 6 | -------------------------------------------------------------------------------- /tests/common/recursive/a.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './b' 3 | ], function (b) { 4 | return 'a'; 5 | }); 6 | -------------------------------------------------------------------------------- /tests/common/recursive/b.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './c', 3 | './d' 4 | ], function (c) { 5 | return 'b'; 6 | }); 7 | -------------------------------------------------------------------------------- /tests/common/recursive/c.js: -------------------------------------------------------------------------------- 1 | define([], 'c'); 2 | -------------------------------------------------------------------------------- /tests/common/recursive/d.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './e' 3 | ], function (e) { 4 | return 'd'; 5 | }); 6 | -------------------------------------------------------------------------------- /tests/common/recursive/e.js: -------------------------------------------------------------------------------- 1 | define([], 'e'); 2 | -------------------------------------------------------------------------------- /tests/common/usesApp.js: -------------------------------------------------------------------------------- 1 | define([ 2 | './app' 3 | ], function (app) { 4 | return app; 5 | }); 6 | -------------------------------------------------------------------------------- /tests/functional/all.ts: -------------------------------------------------------------------------------- 1 | import './basicAmdLoading'; 2 | import './basicCommonJsLoading'; 3 | import './crossOrigin'; 4 | import './csp'; 5 | import './scriptConfigReading'; 6 | import './shimAmdLoading'; 7 | import './webworkerAmd'; 8 | import './require/require'; 9 | -------------------------------------------------------------------------------- /tests/functional/amdApp/Deep2.ts: -------------------------------------------------------------------------------- 1 | import deep3, { Deep4 } from './deep3'; 2 | 3 | class Deep2 { 4 | deep3(): Deep4 { 5 | return deep3(); 6 | } 7 | } 8 | 9 | export default Deep2; 10 | -------------------------------------------------------------------------------- /tests/functional/amdApp/app.ts: -------------------------------------------------------------------------------- 1 | export function getMessage() { 2 | return 'Message from AMD app.'; 3 | } 4 | -------------------------------------------------------------------------------- /tests/functional/amdApp/app1.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'test/module1' 3 | ], function (testModule1) { 4 | return { 5 | getMessage: function () { 6 | return testModule1; 7 | } 8 | }; 9 | }); 10 | -------------------------------------------------------------------------------- /tests/functional/amdApp/circular1.ts: -------------------------------------------------------------------------------- 1 | import circular2 from './circular2'; 2 | 3 | export default function(): string { 4 | return circular2(); 5 | } 6 | 7 | export function getMessage(): string { 8 | return 'circular1.getMessage'; 9 | } 10 | -------------------------------------------------------------------------------- /tests/functional/amdApp/circular2.ts: -------------------------------------------------------------------------------- 1 | import { getMessage as circular1Message } from './circular1'; 2 | 3 | export default function(): string { 4 | return 'circular2'; 5 | } 6 | 7 | export function getMessage(): string { 8 | return circular1Message(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/functional/amdApp/crossOrigin.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var scripts = document.getElementsByTagName('script'), i; 3 | 4 | for (i = 0; i < scripts.length; i++) { 5 | var script = scripts[i]; 6 | 7 | if (script.src && script.src.indexOf('crossOrigin.js') >= 0) { 8 | window.crossOriginResult = { 9 | node: script, 10 | value: script.crossOrigin || 'null' 11 | }; 12 | } 13 | } 14 | })(); 15 | -------------------------------------------------------------------------------- /tests/functional/amdApp/deep1.ts: -------------------------------------------------------------------------------- 1 | import Deep2 from './Deep2'; 2 | import { Deep4 } from './deep3'; 3 | 4 | export default function(): Deep2 { 5 | return new Deep2(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/functional/amdApp/deep3.ts: -------------------------------------------------------------------------------- 1 | import deep4 from './deep4'; 2 | 3 | export type Deep4 = typeof deep4; 4 | 5 | export default function(): Deep4 { 6 | return deep4; 7 | } 8 | -------------------------------------------------------------------------------- /tests/functional/amdApp/deep4.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | objectExport: 'objectExport' 3 | }; 4 | -------------------------------------------------------------------------------- /tests/functional/amdApp/module1.js: -------------------------------------------------------------------------------- 1 | define('test/module1', [], function () { 2 | return 'testModule1'; 3 | }); 4 | -------------------------------------------------------------------------------- /tests/functional/amdApp/module2.js: -------------------------------------------------------------------------------- 1 | define('test/module2', [ 2 | 'test/module1' 3 | ], function (testModule1) { 4 | return { 5 | testModule1Value: testModule1, 6 | testModule2Value: 'testModule2' 7 | }; 8 | }); 9 | -------------------------------------------------------------------------------- /tests/functional/amdApp/module3.js: -------------------------------------------------------------------------------- 1 | define('test/module3', [ 2 | 'amdApp/app' 3 | ], function (app) { 4 | return { 5 | appModuleValue: app.getMessage(), 6 | testModule3Value: 'testModule3' 7 | }; 8 | }); 9 | -------------------------------------------------------------------------------- /tests/functional/amdApp/module4.js: -------------------------------------------------------------------------------- 1 | define({ 2 | aModuleProperty: 'a property value' 3 | }); 4 | -------------------------------------------------------------------------------- /tests/functional/amdFactoryOnly.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic AMD Loading Test 6 | 7 | 8 | 9 | 10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/functional/amdModuleCircular.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tests/functional/amdModuleCircular2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tests/functional/amdModuleCircular3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/functional/amdModuleDeepDeps.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId1a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId2a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId3a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId4a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/functional/amdModuleWithId6a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMD Loading Test 6 | 7 | 8 | 9 | 10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/functional/basicAmdLoading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic AMD Loading Test 6 | 7 | 8 | 9 | 10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/functional/basicAmdLoading.ts: -------------------------------------------------------------------------------- 1 | const { registerSuite } = intern.getInterface('object'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | import executeTest from './executeTest'; 5 | 6 | const AMD_APP_MESSAGE = 'Message from AMD app.'; 7 | 8 | registerSuite('basic AMD loading', { 9 | 'simple test'() { 10 | return executeTest(this, require, './basicAmdLoading.html', function(results: any) { 11 | assert.strictEqual(results.message, AMD_APP_MESSAGE); 12 | }); 13 | }, 14 | 15 | 'AMD module with ID'() { 16 | return executeTest(this, require, './amdModuleWithId1.html', function(results: any) { 17 | assert.strictEqual(results.testModule1Value, 'testModule1', 'Test module should load'); 18 | }); 19 | }, 20 | 21 | 'AMD module with ID - separate module file'() { 22 | return executeTest(this, require, './amdModuleWithId1a.html', function(results: any) { 23 | assert.strictEqual(results.testModule1Value, 'testModule1', 'Test module should load'); 24 | }); 25 | }, 26 | 27 | 'AMD module with ID and dependency - ID'() { 28 | return executeTest(this, require, './amdModuleWithId2.html', function(results: any) { 29 | assert.strictEqual(results.testModule1Value, 'testModule1', 'Dependency module should load'); 30 | assert.strictEqual(results.testModule2Value, 'testModule2', 'Test module should load'); 31 | }); 32 | }, 33 | 34 | 'AMD module with ID and dependency - ID and separate module files'() { 35 | return executeTest(this, require, './amdModuleWithId2a.html', function(results: any) { 36 | assert.strictEqual(results.testModule1Value, 'testModule1', 'Dependency module should load'); 37 | assert.strictEqual(results.testModule2Value, 'testModule2', 'Test module should load'); 38 | }); 39 | }, 40 | 41 | 'AMD module with ID and dependency - module'() { 42 | return executeTest(this, require, './amdModuleWithId3.html', function(results: any) { 43 | assert.strictEqual(results.appModuleValue, AMD_APP_MESSAGE, 'Test module and dependency should load'); 44 | assert.strictEqual(results.testModule3Value, 'testModule3', 'Test module and dependency should load'); 45 | }); 46 | }, 47 | 48 | 'AMD module with ID and dependency - module and separate module files'() { 49 | return executeTest(this, require, './amdModuleWithId3a.html', function(results: any) { 50 | assert.strictEqual(results.appModuleValue, AMD_APP_MESSAGE, 'Test module and dependency should load'); 51 | assert.strictEqual(results.testModule3Value, 'testModule3', 'Test module and dependency should load'); 52 | }); 53 | }, 54 | 55 | 'AMD module without ID and dependency - id'() { 56 | return executeTest(this, require, './amdModuleWithId4.html', function(results: any) { 57 | assert.strictEqual(results, 'testModule1', 'Test module and dependency should load'); 58 | }); 59 | }, 60 | 61 | 'AMD module without ID and dependency - id and separate module files'() { 62 | return executeTest(this, require, './amdModuleWithId4a.html', function(results: any) { 63 | assert.strictEqual(results, 'testModule1', 'Test module and dependency should load'); 64 | }); 65 | }, 66 | 67 | 'AMD module with ID - dependency param omitted'() { 68 | return executeTest(this, require, './amdModuleWithId5.html', function(results: any) { 69 | assert.strictEqual(results.testModule1Value, 'testModule1', 'Test module should load'); 70 | }); 71 | }, 72 | 73 | 'AMD module with ID - no dependencies - object returned'() { 74 | return executeTest(this, require, './amdModuleWithId6.html', function(results: any) { 75 | assert.strictEqual(results.testModuleProperty, 'property value', 'Test module should load'); 76 | }); 77 | }, 78 | 79 | 'AMD module without ID and dependency - separate module file - object returned'() { 80 | return executeTest(this, require, './amdModuleWithId6a.html', function(results: any) { 81 | assert.strictEqual(results.aModuleProperty, 'a property value', 'Test module should load'); 82 | }); 83 | }, 84 | 85 | 'AMD module with circular dependency'() { 86 | const expected = { 87 | default: 'circular2', 88 | message: 'circular1.getMessage' 89 | }; 90 | 91 | return executeTest(this, require, './amdModuleCircular.html', function(results: any) { 92 | assert.deepEqual(results, expected, 'Circular dependency should be resolved'); 93 | }); 94 | }, 95 | 96 | 'AMD module with circular dependency 2'() { 97 | const expected = { 98 | default: 'circular2', 99 | message: 'circular1.getMessage' 100 | }; 101 | 102 | return executeTest(this, require, './amdModuleCircular2.html', function(results: any) { 103 | assert.deepEqual(results, expected, 'Circular dependency should be resolved'); 104 | }); 105 | }, 106 | 107 | 'AMD module with circular dependency 3'() { 108 | const expected = { 109 | c1default: 'circular2', 110 | c1message: 'circular1.getMessage', 111 | c2default: 'circular2', 112 | c2message: 'circular1.getMessage' 113 | }; 114 | 115 | return executeTest(this, require, './amdModuleCircular3.html', function(results: any) { 116 | assert.deepEqual(results, expected, 'Circular dependency should be resolved'); 117 | }); 118 | }, 119 | 120 | 'AMD module with deep dependencies'() { 121 | const expected = { 122 | objectExport: 'objectExport' 123 | }; 124 | 125 | return executeTest(this, require, './amdModuleDeepDeps.html', function(results: any) { 126 | assert.deepEqual(results, expected, 'Deep dependency should be resolved'); 127 | }); 128 | }, 129 | 130 | 'AMD only factory require'() { 131 | const expected = { 132 | property: 'value' 133 | }; 134 | return executeTest(this, require, './amdFactoryOnly.html', function(results: any) { 135 | assert.deepEqual(results, expected, 'Factory only should be resolved'); 136 | }); 137 | } 138 | }); 139 | -------------------------------------------------------------------------------- /tests/functional/basicCommonJsLoading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/functional/basicCommonJsLoading.ts: -------------------------------------------------------------------------------- 1 | const { registerSuite } = intern.getInterface('object'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | import executeTest from './executeTest'; 5 | 6 | const COMMON_JS_APP_MESSAGE = 'Message from CommonJS app.'; 7 | 8 | registerSuite('browser - basic CommonJS loading', { 9 | 'simple test'() { 10 | return executeTest(this, require, './basicCommonJsLoading.html', function(results: any) { 11 | assert.strictEqual(results.message, COMMON_JS_APP_MESSAGE); 12 | }); 13 | }, 14 | 15 | 'CommonJS module with ID'() { 16 | return executeTest(this, require, './commonJsModuleWithId1.html', function(results: any) { 17 | assert.strictEqual(results.testModule1Value, 'testModule1', 'Test module with explicit mid should load'); 18 | }); 19 | }, 20 | 21 | 'CommonJS module with ID and dependency - ID'() { 22 | const expected = { 23 | testModule1Value: 'testModule1', 24 | testModule2Value: 'testModule2' 25 | }; 26 | 27 | return executeTest(this, require, './commonJsModuleWithId2.html', function(results: any) { 28 | assert.deepEqual(results, expected, 'Test modules with explicit mids should load'); 29 | }); 30 | }, 31 | 32 | 'CommonJS module with ID and dependency - module'() { 33 | const expected = { 34 | appModuleValue: COMMON_JS_APP_MESSAGE, 35 | testModule3Value: 'testModule3' 36 | }; 37 | 38 | return executeTest(this, require, './commonJsModuleWithId3.html', function(results: any) { 39 | assert.deepEqual(results, expected, 'Test module and dependency should load'); 40 | }); 41 | }, 42 | 43 | 'CommonJS module without ID and dependency - id'() { 44 | return executeTest(this, require, './commonJsModuleWithId4.html', function(results: any) { 45 | assert.strictEqual(results, 'testModule1', 'Test module and dependency should load'); 46 | }); 47 | }, 48 | 49 | 'CommonJS module with circular dependency'() { 50 | const expected = { 51 | message: 'circular1', 52 | circular2Message: 'circular2' 53 | }; 54 | 55 | return executeTest(this, require, './commonJsModuleCircular.html', function(results: any) { 56 | assert.deepEqual(results, expected, 'Circular dependency should be resolved'); 57 | }); 58 | }, 59 | 60 | 'CommonJS module with circular dependency 2'() { 61 | const expected = { 62 | message: 'circular2', 63 | circular1Message: 'circular1' 64 | }; 65 | 66 | return executeTest(this, require, './commonJsModuleCircular2.html', function(results: any) { 67 | assert.deepEqual(results, expected, 'Circular dependency should be resolved'); 68 | }); 69 | }, 70 | 71 | 'CommonJS module with circular dependency 3'() { 72 | const expected = { 73 | c1message: 'circular1', 74 | c1message2: 'circular2', 75 | c2message: 'circular2', 76 | c2message1: 'circular1' 77 | }; 78 | 79 | return executeTest(this, require, './commonJsModuleCircular3.html', function(results: any) { 80 | assert.deepEqual(results, expected, 'Circular dependency should be resolved'); 81 | }); 82 | }, 83 | 84 | 'CommonJS module with deep dependencies'() { 85 | const expected = { 86 | objectExport: 'objectExport' 87 | }; 88 | 89 | return executeTest(this, require, './commonJsModuleDeepDeps.html', function(results: any) { 90 | assert.deepEqual(results, expected, 'Deep dependency should be resolved'); 91 | }); 92 | } 93 | }); 94 | -------------------------------------------------------------------------------- /tests/functional/commonJsModuleCircular.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/functional/commonJsModuleCircular2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/functional/commonJsModuleCircular3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/functional/commonJsModuleDeepDeps.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/functional/commonJsModuleWithId1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tests/functional/commonJsModuleWithId2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/functional/commonJsModuleWithId3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/functional/commonJsModuleWithId4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CommonJS Loading Test 6 | 7 | 8 | 9 | 10 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/functional/crossOrigin.ts: -------------------------------------------------------------------------------- 1 | const { registerSuite } = intern.getInterface('object'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | import executeTest from './executeTest'; 5 | 6 | registerSuite('Cross origin configuration', { 7 | 'cross origin false'() { 8 | return executeTest(this, require, './crossOriginFalse.html', function(results: any) { 9 | assert.strictEqual(results.message, 'The cross origin value is null'); 10 | }); 11 | }, 12 | 'cross origin anonymous'() { 13 | return executeTest(this, require, './crossOriginAnon.html', function(results: any) { 14 | assert.strictEqual(results.message, 'The cross origin value is anonymous'); 15 | }); 16 | }, 17 | 'cross origin use-credentials'() { 18 | return executeTest(this, require, './crossOriginCreds.html', function(results: any) { 19 | assert.strictEqual(results.message, 'The cross origin value is use-credentials'); 20 | }); 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /tests/functional/crossOriginAnon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic AMD Loading Test 6 | 7 | 8 | 9 | 10 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/functional/crossOriginCreds.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic AMD Loading Test 6 | 7 | 8 | 9 | 10 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/functional/crossOriginFalse.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic AMD Loading Test 6 | 7 | 8 | 9 | 10 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/functional/csp-cdn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CSP with CDN Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/functional/csp-cdn.ts: -------------------------------------------------------------------------------- 1 | require.config({ 2 | packages: [ 3 | { name: 'amdApp', location: './amdApp' }, 4 | { name: 'dojo', location: '//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo' } 5 | ] 6 | }); 7 | 8 | require(['amdApp/app', 'dojo/debounce'], function(app, debounce) { 9 | window.location.href = 'csp-success.html#' + typeof debounce; 10 | }); 11 | -------------------------------------------------------------------------------- /tests/functional/csp-simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Basic CSP Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/functional/csp-simple.ts: -------------------------------------------------------------------------------- 1 | require.config({ 2 | packages: [{ name: 'amdApp', location: './amdApp' }] 3 | }); 4 | 5 | require(['amdApp/app'], function(app) { 6 | window.location.href = 'csp-success.html'; 7 | }); 8 | -------------------------------------------------------------------------------- /tests/functional/csp-success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic CSP Success 6 | 7 | 8 | 9 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/functional/csp.ts: -------------------------------------------------------------------------------- 1 | const { registerSuite } = intern.getInterface('object'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | import executeTest from './executeTest'; 5 | import Node from 'intern/lib/executors/Node'; 6 | 7 | const amdAppMessage = 'Success'; 8 | 9 | let oldShouldInstrument: any; 10 | 11 | /** 12 | * Gotchas for CSP testing 13 | * 14 | * - Selenium Drivers aren't able to inject scripts in most cases, as that violates the CSP rules, so 15 | * the general process is: 16 | * 17 | * - Load HTML page with CSP enabled 18 | * - Load the loader with CSP enabled 19 | * - Load test module with CSP enabled 20 | * - The module, on load, redirects the location to a non-CSP page 21 | * - The final results are read from this non-CSP page 22 | * 23 | * - CSP does not work with instrumentation enabled, but, we want instrumentation in all other cases. As such, we need 24 | * to disable instrumentation for this suite, and re-enable it afterwards. There is no public API for this, so we need 25 | * to perform some Intern wizardry. 26 | */ 27 | registerSuite('AMD loading with CSP enabled', { 28 | before() { 29 | oldShouldInstrument = (this.executor).shouldInstrumentFile; 30 | (this.executor).shouldInstrumentFile = (_filename: string) => false; 31 | }, 32 | 33 | after() { 34 | (this.executor).shouldInstrumentFile = oldShouldInstrument; 35 | }, 36 | 37 | tests: { 38 | simple() { 39 | if (this.remote.session.capabilities.browserName === 'MicrosoftEdge') { 40 | this.skip('CSP tests do not work in Edge'); 41 | } 42 | 43 | return executeTest(this, require, './csp-simple.html', function(results: any) { 44 | assert.strictEqual(results.message, amdAppMessage, 'Local module should load'); 45 | }); 46 | }, 47 | 48 | cdn() { 49 | if (this.remote.session.capabilities.browserName === 'MicrosoftEdge') { 50 | this.skip('CSP tests do not work in Edge'); 51 | } 52 | 53 | const expected = { 54 | message: amdAppMessage, 55 | debounce: '#function' 56 | }; 57 | 58 | return executeTest(this, require, './csp-cdn.html', function(results: any) { 59 | assert.deepEqual(results, expected, 'Local module and CDN module should load'); 60 | }); 61 | } 62 | } 63 | }); 64 | -------------------------------------------------------------------------------- /tests/functional/executeTest.ts: -------------------------------------------------------------------------------- 1 | import Test from 'intern/lib/Test'; 2 | import Command from '@theintern/leadfoot/Command'; 3 | import pollUntil from '@theintern/leadfoot/helpers/pollUntil'; 4 | 5 | export default function( 6 | test: Test, 7 | require: NodeRequire, 8 | htmlTestPath: string, 9 | testFunction: (result: any) => void, 10 | timeout = 10000 11 | ): Command { 12 | return test.remote 13 | .get(require.resolve(htmlTestPath)) 14 | .then( 15 | pollUntil( 16 | function() { 17 | return (window).loaderTestResults; 18 | }, 19 | undefined, 20 | timeout 21 | ), 22 | undefined 23 | ) 24 | .then(testFunction, function() { 25 | throw new Error('loaderTestResult was not set.'); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /tests/functional/map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config map Test 6 | 7 | 8 | 9 | 10 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/functional/require/config/baseUrl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/functional/require/config/defaultConfig.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/functional/require/config/map-hierarchy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/functional/require/config/map-merge.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tests/functional/require/config/map-nested.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /tests/functional/require/config/map-plugin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/functional/require/config/map-relative.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/functional/require/config/map-simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/functional/require/config/map-star.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/functional/require/config/packages1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/functional/require/config/packages2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/functional/require/config/packages3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/functional/require/config/packages4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/functional/require/config/paths1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/functional/require/config/pkg/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | '../../../../common/app' 3 | ], function (app) { 4 | return app; 5 | }); 6 | -------------------------------------------------------------------------------- /tests/functional/require/has.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.has Test 6 | 7 | 8 | 9 | 10 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /tests/functional/require/on/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.undef Test 6 | 7 | 8 | 9 | 10 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /tests/functional/require/on/remove.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.undef Test 6 | 7 | 8 | 9 | 10 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /tests/functional/require/plugin-config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/functional/require/plugin-load.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.config Test 6 | 7 | 8 | 9 | 10 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/functional/require/require.ts: -------------------------------------------------------------------------------- 1 | const { registerSuite } = intern.getInterface('object'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | import Test from 'intern/lib/Test'; 5 | import Command from '@theintern/leadfoot/Command'; 6 | import pollUntil from '@theintern/leadfoot/helpers/pollUntil'; 7 | 8 | function executeTest(suite: Test, htmlTestPath: string, testFn: (result: any) => void, timeout = 5000): Command { 9 | return suite.remote 10 | .get(require.resolve(htmlTestPath)) 11 | .then( 12 | pollUntil( 13 | function() { 14 | return (window).loaderTestResults; 15 | }, 16 | undefined, 17 | timeout 18 | ), 19 | undefined 20 | ) 21 | .then(testFn, function() { 22 | throw new Error('loaderTestResult was not set.'); 23 | }); 24 | } 25 | 26 | const appMessage = 'app'; 27 | 28 | registerSuite('browser - require', { 29 | config: { 30 | baseUrl: { 31 | default(this: any) { 32 | return executeTest(this, './config/defaultConfig.html', function(results: any) { 33 | assert.strictEqual(results, appMessage, '"app" module should load'); 34 | }); 35 | }, 36 | 37 | explicit(this: any) { 38 | return executeTest(this, './config/baseUrl.html', function(results: any) { 39 | assert.strictEqual(results, appMessage, '"app" module should load'); 40 | }); 41 | } 42 | }, 43 | 44 | map: { 45 | star(this: any) { 46 | return executeTest(this, './config/map-star.html', function(results: any) { 47 | assert.strictEqual(results, appMessage, '"app" module should load'); 48 | }); 49 | }, 50 | 51 | simple(this: any) { 52 | return executeTest(this, './config/map-simple.html', function(results: any) { 53 | assert.strictEqual(results.app, appMessage, '"map1" module and dependency should load'); 54 | }); 55 | }, 56 | 57 | hierarchy(this: any) { 58 | return executeTest(this, './config/map-hierarchy.html', function(results: any) { 59 | assert.strictEqual(results.app, 'app A', '"map2" module and dependency should load'); 60 | }); 61 | }, 62 | 63 | merge(this: any) { 64 | return executeTest(this, './config/map-merge.html', function(results: any) { 65 | assert.strictEqual(results.map1App, appMessage, '"map1" module and dependency should load'); 66 | assert.strictEqual(results.map2App, 'app A', '"map2" module and dependency should load'); 67 | }); 68 | }, 69 | 70 | relative(this: any) { 71 | return executeTest(this, './config/map-relative.html', function(results: any) { 72 | assert.strictEqual( 73 | results.app, 74 | appMessage, 75 | '"relative1" module and dependency "common/app" should load' 76 | ); 77 | }); 78 | }, 79 | 80 | nested(this: any) { 81 | return executeTest(this, './config/map-nested.html', function(results: any) { 82 | assert.strictEqual( 83 | results.app, 84 | 'remappedapp', 85 | '"usesApp" module should get remapped "a/remappedApp" module' 86 | ); 87 | assert.strictEqual( 88 | results.remappedApp, 89 | 'remappedapp', 90 | '"remappedApp" module should get unmapped "app" module' 91 | ); 92 | }); 93 | }, 94 | 95 | plugin(this: any) { 96 | return executeTest(this, './config/map-plugin.html', function(results: any) { 97 | assert.strictEqual(results.plugin1, 'one', 'Plug-in module should load'); 98 | assert.strictEqual(results.plugin2, 'two', 'Plug-in module should load'); 99 | }); 100 | } 101 | }, 102 | 103 | packages: { 104 | 'name and location'(this: any) { 105 | return executeTest(this, './config/packages1.html', function(results: any) { 106 | assert.strictEqual(results, appMessage, '"app" module should load'); 107 | }); 108 | }, 109 | 110 | 'name, location and main'(this: any) { 111 | return executeTest(this, './config/packages2.html', function(results: any) { 112 | assert.strictEqual(results, appMessage, '"app" module should load'); 113 | }); 114 | }, 115 | 116 | 'package name with slashes'(this: any) { 117 | return executeTest(this, './config/packages3.html', function(results: any) { 118 | assert.strictEqual(results, appMessage, '"app" module should load'); 119 | }); 120 | }, 121 | 122 | 'nested packages'(this: any) { 123 | return executeTest(this, './config/packages4.html', function(results: any) { 124 | assert.strictEqual(results, appMessage, '"app" module should load'); 125 | }); 126 | } 127 | }, 128 | 129 | paths: { 130 | simple(this: any) { 131 | return executeTest(this, './config/paths1.html', function(results: any) { 132 | assert.strictEqual(results, appMessage, '"app" module should load'); 133 | }); 134 | } 135 | } 136 | }, 137 | 138 | plugin: { 139 | load(this: any) { 140 | return executeTest(this, './plugin-load.html', function(results: any) { 141 | assert.strictEqual(results, 'one', 'Plug-in module should load'); 142 | }); 143 | }, 144 | config(this: any) { 145 | return executeTest(this, './plugin-config.html', function(results: any) { 146 | if (results !== 'success') { 147 | assert.fail(null, null, results); 148 | } 149 | }); 150 | } 151 | }, 152 | 153 | has(this: any) { 154 | return executeTest(this, './has.html', function(results: any) { 155 | if (results !== 'success') { 156 | assert.fail(null, null, results); 157 | } 158 | }); 159 | }, 160 | 161 | toAbsMid(this: any) { 162 | return executeTest(this, './toAbsMid.html', function(results: any) { 163 | if (results !== 'success') { 164 | assert.fail(null, null, results); 165 | } 166 | }); 167 | }, 168 | 169 | toUrl(this: any) { 170 | return executeTest(this, './toUrl.html', function(results: any) { 171 | if (results !== 'success') { 172 | assert.fail(null, null, results); 173 | } 174 | }); 175 | }, 176 | 177 | undef(this: any) { 178 | return executeTest(this, './undef.html', function(results: any) { 179 | if (results !== 'success') { 180 | assert.fail(null, null, results); 181 | } 182 | }); 183 | }, 184 | 185 | on: { 186 | error(this: any) { 187 | return executeTest(this, './on/error.html', function(results: any) { 188 | if (results !== 'success') { 189 | assert.fail(null, null, results); 190 | } 191 | }); 192 | }, 193 | 194 | remove(this: any) { 195 | return executeTest(this, './on/remove.html', function(results: any) { 196 | if (results !== 'success') { 197 | assert.fail(null, null, results); 198 | } 199 | }); 200 | } 201 | } 202 | }); 203 | -------------------------------------------------------------------------------- /tests/functional/require/toAbsMid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.toAbsMid Test 6 | 7 | 8 | 9 | 10 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tests/functional/require/toUrl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.toUrl Test 6 | 7 | 8 | 9 | 10 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tests/functional/require/undef.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | require.undef Test 6 | 7 | 8 | 9 | 10 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /tests/functional/scriptConfigReading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Script Config Reading Test 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/functional/scriptConfigReading.ts: -------------------------------------------------------------------------------- 1 | const { registerSuite } = intern.getInterface('object'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | import executeTest from './executeTest'; 5 | 6 | const AMD_APP_MESSAGE = 'Message from AMD app.'; 7 | 8 | registerSuite('Script tag configuration', { 9 | 'script tag config'() { 10 | return executeTest(this, require, './scriptConfigReading.html', function(results: any) { 11 | assert.strictEqual(results.message, AMD_APP_MESSAGE); 12 | }); 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /tests/functional/shimAmdLoading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Shim AMD Loading Test 6 | 7 | 8 | 9 | 10 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /tests/functional/shimAmdLoading.ts: -------------------------------------------------------------------------------- 1 | const { registerSuite } = intern.getInterface('object'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | import executeTest from './executeTest'; 5 | 6 | registerSuite('Shim API AMD loading', { 7 | 'shim tests'() { 8 | return executeTest(this, require, './shimAmdLoading.html', function(results: any) { 9 | assert.strictEqual(results.stringValue, 'string', 'Global value should have been read from nested path'); 10 | assert.strictEqual(results.numberValue, 5, 'Init return value should be used as module value'); 11 | assert.strictEqual(results.initTwice, 1, 'Module init function should only be called once'); 12 | assert.strictEqual(results.addedValues, 8, 'Module dependencies should have resolved'); 13 | assert.strictEqual( 14 | results.pluginDep, 15 | 'plugin-dep', 16 | 'Module dependencies should have loaded with no exports' 17 | ); 18 | assert.isUndefined( 19 | results.initNotReturn, 20 | 'Empty module export and init function should result in empty object' 21 | ); 22 | }); 23 | }, 24 | 25 | 'non-existent global variable'() { 26 | return executeTest(this, require, './shimAmdLoading2.html', function(results: any) { 27 | assert.strictEqual( 28 | results.error, 29 | 'Tried to find badVariable but it did not exist', 30 | 'Non existent global variable expected to error' 31 | ); 32 | }); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /tests/functional/shimAmdLoading2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Shim AMD Loading Test 6 | 7 | 8 | 9 | 10 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/functional/webworkerAmd.ts: -------------------------------------------------------------------------------- 1 | const { registerSuite } = intern.getInterface('object'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | import executeTest from './executeTest'; 5 | 6 | const AMD_APP_MESSAGE = 'Message from AMD app.'; 7 | 8 | registerSuite('AMD loading in web worker', { 9 | 'basic loading'() { 10 | return executeTest(this, require, './webworkerBasic.html', function(results: any) { 11 | assert.strictEqual(results.message, AMD_APP_MESSAGE); 12 | }); 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /tests/functional/webworkerBasic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 20 | 21 | -------------------------------------------------------------------------------- /tests/functional/worker.ts: -------------------------------------------------------------------------------- 1 | declare function importScripts(url: string): void; 2 | 3 | onmessage = function(e) { 4 | try { 5 | /* load the loader */ 6 | importScripts('../../src/loader.js'); 7 | 8 | require.config({ 9 | packages: [{ name: 'amdApp', location: './amdApp' }] 10 | }); 11 | 12 | require(['amdApp/app'], function(app) { 13 | /* post message back with the results */ 14 | (postMessage)({ 15 | message: app.getMessage() 16 | }); 17 | }); 18 | } catch (e) { 19 | (postMessage)({ 20 | message: e.message, 21 | status: 'fail' 22 | }); 23 | throw e; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /tests/interfaces.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace NodeJS { 2 | interface Global { 3 | require: DojoLoader.RootRequire; 4 | define: DojoLoader.Define; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/module.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dojo/loader/147cb45a67a4de9a411c388af0047ae8bdd4d5aa/tests/module.d.ts -------------------------------------------------------------------------------- /tests/run.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Intern suite 6 | 7 | 8 | 9 | Redirecting to Intern client 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/support/util.ts: -------------------------------------------------------------------------------- 1 | export function isEventuallyRejected(promise: Promise): Promise { 2 | return promise.then( 3 | function() { 4 | throw new Error('unexpected code path'); 5 | }, 6 | (() => { 7 | return true; // expect rejection 8 | }) 9 | ); 10 | } 11 | 12 | export function throwImmediatly() { 13 | throw new Error('unexpected code path'); 14 | } 15 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "umd" 5 | }, 6 | "include": [ 7 | "./**/*.ts", 8 | "../src/interfaces.d.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /tests/unit/all-node.ts: -------------------------------------------------------------------------------- 1 | import './basicCommonJsLoading'; 2 | import './require'; 3 | -------------------------------------------------------------------------------- /tests/unit/all.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dojo/loader/147cb45a67a4de9a411c388af0047ae8bdd4d5aa/tests/unit/all.ts -------------------------------------------------------------------------------- /tests/unit/bad-module.js: -------------------------------------------------------------------------------- 1 | %6238ff230 2 | -------------------------------------------------------------------------------- /tests/unit/basicCommonJsLoading.ts: -------------------------------------------------------------------------------- 1 | intern.getInterface('object').registerSuite('basic CommonJS loading', () => { 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | const COMMON_JS_APP_MESSAGE = 'Message from CommonJS app.'; 5 | const DEFAULT_TIMEOUT = 1000; 6 | 7 | let globalErrorHandler: any; 8 | let originalDefine: any; 9 | let originalRequire: any; 10 | 11 | function setErrorHandler(dfd: any) { 12 | (process)._events.uncaughtException = function(error: Error) { 13 | dfd.reject(error); 14 | }; 15 | } 16 | 17 | function reloadLoader() { 18 | let loaderPath = require.resolve('../../src/loader.js'); 19 | 20 | global.define = null; 21 | global.require = null; 22 | 23 | if (require.cache) { 24 | delete require.cache[loaderPath]; 25 | } 26 | 27 | require(loaderPath); 28 | } 29 | 30 | return { 31 | before() { 32 | originalDefine = global.define; 33 | originalRequire = global.require; 34 | }, 35 | 36 | after() { 37 | global.define = originalDefine; 38 | global.require = originalRequire; 39 | }, 40 | 41 | beforeEach() { 42 | // Do this before each test to ensure a clean loader environment with empty cache 43 | reloadLoader(); 44 | 45 | global.require.config({ 46 | packages: [ 47 | { 48 | name: 'commonJs', 49 | location: './tests/common/commonJs' 50 | } 51 | ] 52 | }); 53 | 54 | // Need to handle global errors to catch errors thrown by 'require' or 'define' 55 | // otherwise the whole test suite dies 56 | // Note: process.on('uncaughtException') does not work 57 | globalErrorHandler = (process)._events.uncaughtException; 58 | delete (process)._events.uncaughtException; 59 | }, 60 | 61 | afterEach() { 62 | (process)._events.uncaughtException = globalErrorHandler; 63 | }, 64 | 65 | tests: { 66 | 'simple test'(this: any) { 67 | let dfd = this.async(DEFAULT_TIMEOUT); 68 | 69 | setErrorHandler(dfd); 70 | 71 | global.require( 72 | ['commonJs/app'], 73 | dfd.callback(function(app: any) { 74 | assert.strictEqual(app.getMessage(), COMMON_JS_APP_MESSAGE); 75 | }) 76 | ); 77 | }, 78 | 79 | 'CommonJS module with ID'(this: any) { 80 | let dfd = this.async(DEFAULT_TIMEOUT); 81 | 82 | setErrorHandler(dfd); 83 | 84 | global.require( 85 | ['require', 'commonJs/testModule1'], 86 | dfd.callback(function(require: any) { 87 | let testModule1 = require('test/module1'); 88 | 89 | assert.strictEqual(testModule1, 'testModule1', 'Test module with explicit mid should load'); 90 | }) 91 | ); 92 | }, 93 | 94 | 'CommonJS module with ID and dependency - ID'(this: any) { 95 | const expected = { 96 | testModule1Value: 'testModule1', 97 | testModule2Value: 'testModule2' 98 | }; 99 | 100 | let dfd = this.async(DEFAULT_TIMEOUT); 101 | 102 | setErrorHandler(dfd); 103 | 104 | global.require( 105 | ['require', 'commonJs/testModule1', 'commonJs/testModule2'], 106 | dfd.callback(function(require: any) { 107 | let testModule2 = require('test/module2'); 108 | 109 | assert.deepEqual(testModule2, expected, 'Test modules with explicit mids should load'); 110 | }) 111 | ); 112 | }, 113 | 114 | 'CommonJS module with ID and dependency - module'(this: any) { 115 | const expected = { 116 | appModuleValue: COMMON_JS_APP_MESSAGE, 117 | testModule3Value: 'testModule3' 118 | }; 119 | 120 | let dfd = this.async(DEFAULT_TIMEOUT); 121 | 122 | setErrorHandler(dfd); 123 | 124 | global.require( 125 | ['require', 'commonJs/testModule3'], 126 | dfd.callback(function(require: any) { 127 | let testModule3 = require('test/module3'); 128 | 129 | assert.deepEqual(testModule3, expected, 'Test module and dependency should load'); 130 | }) 131 | ); 132 | }, 133 | 134 | 'CommonJS module without ID and dependency - id'(this: any) { 135 | const expected = { 136 | testModule1Value: 'testModule1', 137 | testModule2Value: 'testModule2' 138 | }; 139 | 140 | let dfd = this.async(DEFAULT_TIMEOUT); 141 | 142 | setErrorHandler(dfd); 143 | 144 | // 'commonJs/testModule1.js' specifies its mid explicitly ('test/module1'), so we have to specify it by filepath 145 | // to get it load initially. 'commonJs/app1' specifies 'test/module1' as a dependency, so we need to ensure 146 | // 'commonJs/testModule1.js' has been loaded before we attempt to load 'commonJs/app1' 147 | global.require(['require', 'commonJs/testModule1'], function(require: any) { 148 | require(['commonJs/app1'], dfd.callback(function(app1: any) { 149 | assert.strictEqual( 150 | app1.getMessage(), 151 | expected.testModule1Value, 152 | 'Test module and dependency should load' 153 | ); 154 | })); 155 | }); 156 | }, 157 | 158 | 'CommonJS module with circular dependency'(this: any) { 159 | let dfd = this.async(DEFAULT_TIMEOUT); 160 | 161 | setErrorHandler(dfd); 162 | 163 | global.require( 164 | ['commonJs/circular1'], 165 | dfd.callback(function(circular1: any) { 166 | assert.strictEqual( 167 | circular1.getMessage(), 168 | 'circular1', 169 | 'Circular dependency should be resolved' 170 | ); 171 | assert.strictEqual( 172 | circular1.circular2Message(), 173 | 'circular2', 174 | 'Circular dependency should be resolved' 175 | ); 176 | }) 177 | ); 178 | }, 179 | 180 | 'CommonJS module with circular dependency 2'(this: any) { 181 | let dfd = this.async(DEFAULT_TIMEOUT); 182 | 183 | setErrorHandler(dfd); 184 | 185 | global.require( 186 | ['commonJs/circular2'], 187 | dfd.callback(function(circular2: any) { 188 | assert.strictEqual( 189 | circular2.getMessage(), 190 | 'circular2', 191 | 'Circular dependency should be resolved' 192 | ); 193 | assert.strictEqual( 194 | circular2.circular1Message(), 195 | 'circular1', 196 | 'Circular dependency should be resolved' 197 | ); 198 | }) 199 | ); 200 | }, 201 | 202 | 'CommonJS module with circular dependency 3'(this: any) { 203 | let dfd = this.async(DEFAULT_TIMEOUT); 204 | 205 | setErrorHandler(dfd); 206 | 207 | global.require( 208 | ['commonJs/circular1', 'commonJs/circular2'], 209 | dfd.callback(function(circular1: any, circular2: any) { 210 | assert.strictEqual( 211 | circular1.getMessage(), 212 | 'circular1', 213 | 'Circular dependency should be resolved' 214 | ); 215 | assert.strictEqual( 216 | circular1.circular2Message(), 217 | 'circular2', 218 | 'Circular dependency should be resolved' 219 | ); 220 | assert.strictEqual( 221 | circular2.getMessage(), 222 | 'circular2', 223 | 'Circular dependency should be resolved' 224 | ); 225 | assert.strictEqual( 226 | circular2.circular1Message(), 227 | 'circular1', 228 | 'Circular dependency should be resolved' 229 | ); 230 | }) 231 | ); 232 | }, 233 | 234 | 'CommonJS module with deep dependencies'(this: any) { 235 | const expected = { 236 | objectExport: 'objectExport' 237 | }; 238 | 239 | let dfd = this.async(DEFAULT_TIMEOUT); 240 | 241 | setErrorHandler(dfd); 242 | 243 | global.require( 244 | ['commonJs/deep1'], 245 | dfd.callback(function(deep1: any) { 246 | let obj = deep1(); 247 | 248 | assert.isObject(obj, 'deep1() should create an object'); 249 | assert.deepEqual(obj.deep3(), expected, 'deep3() should create an object'); 250 | }) 251 | ); 252 | } 253 | } 254 | }; 255 | }); 256 | -------------------------------------------------------------------------------- /tests/unit/require.ts: -------------------------------------------------------------------------------- 1 | intern.getInterface('object').registerSuite('require', () => { 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | const DEFAULT_TIMEOUT = 1000; 5 | 6 | let globalErrorHandler: any; 7 | let originalDefine: any; 8 | let originalRequire: any; 9 | let onErrorHandler: any; 10 | 11 | function setErrorHandler(dfd: any) { 12 | (process)._events.uncaughtException = function(error: Error) { 13 | dfd.reject(error); 14 | }; 15 | } 16 | 17 | function reloadLoader() { 18 | let loaderPath = require.resolve('../../src/loader.js'); 19 | 20 | global.define = null; 21 | global.require = null; 22 | delete require.cache[loaderPath]; 23 | require(loaderPath); 24 | } 25 | 26 | return { 27 | before() { 28 | originalDefine = global.define; 29 | originalRequire = global.require; 30 | }, 31 | 32 | after() { 33 | global.define = originalDefine; 34 | global.require = originalRequire; 35 | }, 36 | 37 | beforeEach() { 38 | // Do this before each test to ensure a clean loader environment with empty cache 39 | reloadLoader(); 40 | 41 | // Need to handle global errors to catch errors thrown by 'require' or 'define' 42 | // otherwise the whole test suite dies 43 | // Note: process.on('uncaughtException') does not work 44 | globalErrorHandler = (process)._events.uncaughtException; 45 | delete (process)._events.uncaughtException; 46 | }, 47 | 48 | afterEach() { 49 | (process)._events.uncaughtException = globalErrorHandler; 50 | if (onErrorHandler) { 51 | onErrorHandler.remove(); 52 | onErrorHandler = undefined; 53 | } 54 | }, 55 | 56 | tests: { 57 | 'node modules'(this: any) { 58 | let dfd = this.async(DEFAULT_TIMEOUT); 59 | 60 | setErrorHandler(dfd); 61 | 62 | global.require( 63 | [ 64 | // This module exists in the "node_modules" folder, so the loader will fail to locate it, but should 65 | // use the Node.js 'require' to load it, which should succeed (since Node.js automatically checks 66 | // the "node_modules" folder) 67 | 'grunt/lib/grunt/option', 68 | '_build/tests/common/app' 69 | ], 70 | dfd.callback(function(gruntOption: any, app: any) { 71 | assert.isFunction(gruntOption, '"grunt/option" module should load and be a function'); 72 | assert.isFunction(gruntOption.init, '"grunt/option" module should load and be valid'); 73 | assert.strictEqual(app, 'app', '"app" module should load'); 74 | }) 75 | ); 76 | }, 77 | 78 | 'node modules sync'() { 79 | const events: any = global.require('events'); 80 | assert.isNotNull(events); 81 | assert.isNotNull(events.EventEmitter); 82 | }, 83 | 84 | 'node modules sync multiples'() { 85 | const events: any = global.require('events'); 86 | assert.isNotNull(events); 87 | assert.isNotNull(events.EventEmitter); 88 | 89 | const eventsAgain = global.require('events'); 90 | assert.strictEqual(eventsAgain, events); 91 | }, 92 | 93 | 'non-existent module'(this: any) { 94 | let dfd = this.async(DEFAULT_TIMEOUT); 95 | 96 | (process)._events.uncaughtException = function(error: Error) { 97 | if (error.message.indexOf('bad/module/id') === -1) { 98 | dfd.reject(error); 99 | } else { 100 | dfd.resolve(); 101 | } 102 | }; 103 | 104 | global.require( 105 | ['bad/module/id'], 106 | dfd.rejectOnError(function(gruntOption: any, app: any) { 107 | assert.fail(null, null, 'Dependency with bad module id should not be resolved'); 108 | }) 109 | ); 110 | }, 111 | 112 | 'non-existent module sync'() { 113 | assert.throws(function() { 114 | global.require('thisIsNotAValidNodeModule'); 115 | }); 116 | }, 117 | 118 | 'non-existent module with on-error listener should not throw error'(this: any) { 119 | let dfd = this.async(DEFAULT_TIMEOUT); 120 | let badMid = 'bad/module/id'; 121 | 122 | (process)._events.uncaughtException = function(error: Error) { 123 | if (error.message.indexOf(badMid) > -1) { 124 | dfd.reject(error); 125 | } 126 | }; 127 | 128 | onErrorHandler = global.require.on( 129 | 'error', 130 | dfd.callback(function noop(error: DojoLoader.LoaderError) {}) 131 | ); 132 | 133 | global.require([badMid], function() { 134 | dfd.reject(new Error('Dependency with bad module id should not be resolved')); 135 | }); 136 | }, 137 | 138 | 'non-existent module with on-error listener should fire callback'(this: any) { 139 | let dfd = this.async(DEFAULT_TIMEOUT); 140 | let badMid = 'bad/module/id'; 141 | 142 | onErrorHandler = global.require.on( 143 | 'error', 144 | dfd.callback(function(error: DojoLoader.LoaderError) { 145 | assert.isTrue( 146 | error.message.indexOf(badMid) > -1, 147 | 'Callback should fire and message should contain bad mid' 148 | ); 149 | }) 150 | ); 151 | 152 | global.require([badMid], function() { 153 | dfd.reject(new Error('Dependency with bad module id should not be resolved')); 154 | }); 155 | }, 156 | 157 | 'non-existent module with on-error listener should provide info'(this: any) { 158 | let dfd = this.async(DEFAULT_TIMEOUT); 159 | let badMid = 'bad/module/id'; 160 | 161 | onErrorHandler = global.require.on( 162 | 'error', 163 | dfd.callback(function(error: DojoLoader.LoaderError) { 164 | assert.strictEqual(error.src, 'dojo/loader', 'Error should be marked as from the loader'); 165 | assert.isObject(error.info, 'Error should be supplemented with info'); 166 | assert.strictEqual(error.info.module.mid, badMid, 'Error should be related to the bad module'); 167 | assert.strictEqual( 168 | error.info.url, 169 | badMid + '.js', 170 | 'Error should contain the URL of the bad module' 171 | ); 172 | }) 173 | ); 174 | 175 | global.require([badMid], function() { 176 | dfd.reject(new Error('Dependency with bad module id should not be resolved')); 177 | }); 178 | }, 179 | 180 | 'specific module errors are reported'(this: any) { 181 | let badMid = 'tests/unit/bad-module'; 182 | let dfd = this.async(); 183 | 184 | onErrorHandler = global.require.on( 185 | 'error', 186 | dfd.callback(function(error: DojoLoader.LoaderError) { 187 | assert.include(error.info.details || '', 'Unexpected token'); 188 | }) 189 | ); 190 | 191 | global.require([badMid], function() { 192 | dfd.reject('Should not have resolved'); 193 | }); 194 | }, 195 | 196 | 'missing module errors are reported'(this: any) { 197 | let badMid = 'bad/module/id'; 198 | let dfd = this.async(); 199 | 200 | onErrorHandler = global.require.on( 201 | 'error', 202 | dfd.callback(function(error: DojoLoader.LoaderError) { 203 | assert.include(error.info.details || '', 'Cannot find module'); 204 | }) 205 | ); 206 | 207 | global.require([badMid], function() { 208 | dfd.reject('Should not have resolved'); 209 | }); 210 | }, 211 | 212 | 'on-error listener should be removable'(this: any) { 213 | let dfd = this.async(DEFAULT_TIMEOUT); 214 | let badMid = 'bad/module/id'; 215 | 216 | onErrorHandler = global.require.on( 217 | 'error', 218 | dfd.callback(function(error: DojoLoader.LoaderError) { 219 | assert.fail(null, null, 'on-error callback should not have fired'); 220 | }) 221 | ); 222 | onErrorHandler.remove(); 223 | 224 | (process)._events.uncaughtException = dfd.callback(function(error: DojoLoader.LoaderError) { 225 | assert.isTrue(error.message.indexOf(badMid) > -1, 'Error should be related to bad module'); 226 | }); 227 | 228 | global.require([badMid], function() { 229 | dfd.reject(new Error('Dependency with bad module id should not be resolved')); 230 | }); 231 | }, 232 | 233 | 'only factory AMD require'(this: any) { 234 | let dfd = this.async(DEFAULT_TIMEOUT); 235 | 236 | setErrorHandler(dfd); 237 | 238 | global.require( 239 | ['_build/tests/common/amd/onlyFactory'], 240 | dfd.callback(function(onlyFactory: any) { 241 | assert.strictEqual( 242 | onlyFactory.property, 243 | 'value', 244 | 'AMD module with no dependencies should load' 245 | ); 246 | }) 247 | ); 248 | }, 249 | 250 | config: { 251 | baseUrl: { 252 | default(this: any) { 253 | let dfd = this.async(DEFAULT_TIMEOUT); 254 | 255 | setErrorHandler(dfd); 256 | 257 | global.require( 258 | ['_build/tests/common/app'], 259 | dfd.callback(function(app: any) { 260 | assert.strictEqual(app, 'app', '"app" module should load'); 261 | }) 262 | ); 263 | }, 264 | 265 | explicit(this: any) { 266 | let dfd = this.async(DEFAULT_TIMEOUT); 267 | 268 | setErrorHandler(dfd); 269 | 270 | global.require.config({ 271 | baseUrl: './_build/tests' 272 | }); 273 | 274 | global.require( 275 | ['common/app'], 276 | dfd.callback(function(app: any) { 277 | assert.strictEqual(app, 'app', '"app" module should load'); 278 | }) 279 | ); 280 | } 281 | }, 282 | 283 | map: { 284 | star(this: any) { 285 | let dfd = this.async(DEFAULT_TIMEOUT); 286 | 287 | setErrorHandler(dfd); 288 | 289 | global.require.config({ 290 | map: { 291 | '*': { 292 | mapped: './_build/tests/common' 293 | } 294 | } 295 | }); 296 | 297 | global.require( 298 | ['mapped/app'], 299 | dfd.callback(function(app: any) { 300 | assert.strictEqual(app, 'app', '"app" module should load'); 301 | }) 302 | ); 303 | }, 304 | 305 | simple(this: any) { 306 | let dfd = this.async(DEFAULT_TIMEOUT); 307 | 308 | setErrorHandler(dfd); 309 | 310 | global.require.config({ 311 | map: { 312 | common: { 313 | mapped: './_build/tests/common' 314 | } 315 | }, 316 | packages: [ 317 | { 318 | name: 'common', 319 | location: './_build/tests/common' 320 | } 321 | ] 322 | }); 323 | 324 | global.require( 325 | ['common/map1'], 326 | dfd.callback(function(map1: any) { 327 | assert.strictEqual(map1.app, 'app', '"map1" module and dependency should load'); 328 | }) 329 | ); 330 | }, 331 | 332 | hierarchy(this: any) { 333 | let dfd = this.async(DEFAULT_TIMEOUT); 334 | 335 | setErrorHandler(dfd); 336 | 337 | global.require.config({ 338 | map: { 339 | common: { 340 | mapped: './_build/tests/common' 341 | }, 342 | 'common/a': { 343 | mapped: './_build/tests/common/a' 344 | } 345 | }, 346 | packages: [ 347 | { 348 | name: 'common', 349 | location: './_build/tests/common' 350 | } 351 | ] 352 | }); 353 | 354 | global.require( 355 | ['common/a/map2'], 356 | dfd.callback(function(map2: any) { 357 | assert.strictEqual(map2.app, 'app A', '"map2" module and dependency should load'); 358 | }) 359 | ); 360 | }, 361 | 362 | merge(this: any) { 363 | let dfd = this.async(DEFAULT_TIMEOUT); 364 | 365 | setErrorHandler(dfd); 366 | 367 | global.require.config({ 368 | map: { 369 | common: { 370 | mapped: './_build/tests/common' 371 | } 372 | }, 373 | packages: [ 374 | { 375 | name: 'common', 376 | location: './_build/tests/common' 377 | } 378 | ] 379 | }); 380 | 381 | global.require.config({ 382 | map: { 383 | 'common/a': { 384 | mapped: './_build/tests/common/a' 385 | } 386 | } 387 | }); 388 | 389 | global.require( 390 | ['common/map1', 'common/a/map2'], 391 | dfd.callback(function(map1: any, map2: any) { 392 | assert.strictEqual(map1.app, 'app', '"map1" module and dependency should load'); 393 | assert.strictEqual(map2.app, 'app A', '"map2" module and dependency should load'); 394 | }) 395 | ); 396 | }, 397 | 398 | relative(this: any) { 399 | let dfd = this.async(DEFAULT_TIMEOUT); 400 | 401 | setErrorHandler(dfd); 402 | 403 | global.require.config({ 404 | map: { 405 | 'common/a': { 406 | 'common/a': './_build/tests/common' 407 | } 408 | }, 409 | packages: [ 410 | { 411 | name: 'common', 412 | location: './_build/tests/common' 413 | } 414 | ] 415 | }); 416 | 417 | global.require( 418 | ['common/a/relative1'], 419 | dfd.callback(function(relative1: any) { 420 | assert.strictEqual( 421 | relative1.app, 422 | 'app', 423 | '"relative1" module and dependency "common/app" should load' 424 | ); 425 | }) 426 | ); 427 | }, 428 | 429 | nested(this: any) { 430 | let dfd = this.async(DEFAULT_TIMEOUT); 431 | 432 | setErrorHandler(dfd); 433 | 434 | global.require.config({ 435 | map: { 436 | '*': { 437 | 'common/app': 'common/a/remappedApp' 438 | }, 439 | 'common/a/remappedApp': { 440 | 'common/app': 'common/app' 441 | } 442 | }, 443 | packages: [ 444 | { 445 | name: 'common', 446 | location: './_build/tests/common' 447 | } 448 | ] 449 | }); 450 | 451 | global.require( 452 | ['common/usesApp', 'common/a/remappedApp'], 453 | dfd.callback(function(app: any, remappedApp: any) { 454 | assert.strictEqual( 455 | app, 456 | 'remappedapp', 457 | '"usesApp" module should get remapped "a/remappedApp" module' 458 | ); 459 | assert.strictEqual( 460 | remappedApp, 461 | 'remappedapp', 462 | '"remappedApp" module should get unmapped "app" module' 463 | ); 464 | }) 465 | ); 466 | }, 467 | 468 | plugin(this: any) { 469 | let dfd = this.async(DEFAULT_TIMEOUT); 470 | 471 | setErrorHandler(dfd); 472 | 473 | global.require.config({ 474 | map: { 475 | '*': { 476 | plugin: 'common/plugin', 477 | plugin2: 'common/plugin!two' 478 | } 479 | }, 480 | packages: [ 481 | { 482 | name: 'common', 483 | location: './_build/tests/common' 484 | } 485 | ] 486 | }); 487 | 488 | global.require( 489 | ['plugin!one', 'plugin2'], 490 | dfd.callback(function(plugin1: any, plugin2: any) { 491 | assert.strictEqual(plugin1, 'one', 'Plug-in module should load'); 492 | assert.strictEqual(plugin2, 'two', 'Plug-in module should load'); 493 | }) 494 | ); 495 | } 496 | }, 497 | 498 | packages: { 499 | 'name and location'(this: any) { 500 | let dfd = this.async(DEFAULT_TIMEOUT); 501 | 502 | setErrorHandler(dfd); 503 | 504 | global.require.config({ 505 | packages: [ 506 | { 507 | name: 'common', 508 | location: './_build/tests/common' 509 | } 510 | ] 511 | }); 512 | 513 | global.require( 514 | ['common/app'], 515 | dfd.callback(function(app: any) { 516 | assert.strictEqual(app, 'app', '"app" module should load'); 517 | }) 518 | ); 519 | }, 520 | 521 | 'name, location and main'(this: any) { 522 | let dfd = this.async(DEFAULT_TIMEOUT); 523 | 524 | setErrorHandler(dfd); 525 | 526 | global.require.config({ 527 | packages: [ 528 | { 529 | name: 'common', 530 | location: './_build/tests/common', 531 | main: 'app' 532 | } 533 | ] 534 | }); 535 | 536 | global.require( 537 | ['common'], 538 | dfd.callback(function(app: any) { 539 | assert.strictEqual(app, 'app', '"app" module should load'); 540 | }) 541 | ); 542 | }, 543 | 'slashes in package name'(this: any) { 544 | let dfd = this.async(DEFAULT_TIMEOUT); 545 | 546 | setErrorHandler(dfd); 547 | 548 | global.require.config({ 549 | packages: [ 550 | { 551 | name: '@test/common', 552 | location: './_build/tests/common', 553 | main: 'app' 554 | } 555 | ] 556 | }); 557 | 558 | global.require( 559 | ['@test/common'], 560 | dfd.callback(function(app: any) { 561 | assert.strictEqual(app, 'app', '"app" module should load'); 562 | }) 563 | ); 564 | }, 565 | 'single @ package'(this: any) { 566 | let dfd = this.async(DEFAULT_TIMEOUT); 567 | 568 | setErrorHandler(dfd); 569 | 570 | global.require.config({ 571 | packages: [ 572 | { 573 | name: '@test', 574 | location: './_build/tests', 575 | main: 'app' 576 | } 577 | ] 578 | }); 579 | 580 | global.require( 581 | ['@test/common/app'], 582 | dfd.callback(function(app: any) { 583 | assert.strictEqual(app, 'app', '"app" module should load'); 584 | }) 585 | ); 586 | } 587 | }, 588 | 589 | paths: { 590 | simple(this: any) { 591 | let dfd = this.async(DEFAULT_TIMEOUT); 592 | 593 | setErrorHandler(dfd); 594 | 595 | global.require.config({ 596 | paths: { 597 | common: '_build/tests/common' 598 | } 599 | }); 600 | 601 | global.require( 602 | ['common/app'], 603 | dfd.callback(function(app: any) { 604 | assert.strictEqual(app, 'app', '"app" module should load'); 605 | }) 606 | ); 607 | } 608 | } 609 | }, 610 | 611 | has: { 612 | 'has API is available'() { 613 | assert.instanceOf(global.require.has, Function, "'require.has' should be a function"); 614 | assert.instanceOf(global.require.has.add, Function, "'require.has.add' should be a function"); 615 | }, 616 | 617 | add() { 618 | global.require.has.add('test1', 'test1'); 619 | assert.strictEqual(global.require.has('test1'), 'test1'); 620 | assert.isUndefined(global.require.has('test2'), 'Undefined test should be undefined'); 621 | 622 | global.require.has.add('test1', 'NEW VALUE'); 623 | assert.strictEqual(global.require.has('test1'), 'test1', 'Re-adding same-name test should fail'); 624 | 625 | global.require.has.add('test1', 'NEW VALUE', false, true); 626 | assert.strictEqual( 627 | global.require.has('test1'), 628 | 'NEW VALUE', 629 | 'Re-adding same-name test with force parameter should succeed' 630 | ); 631 | 632 | let runCount = 0; 633 | global.require.has.add('test2', function() { 634 | runCount += 1; 635 | return runCount; 636 | }); 637 | assert.strictEqual(runCount, 0, 'has test should not execute immediately'); 638 | 639 | global.require.has.add( 640 | 'test3', 641 | function() { 642 | runCount += 1; 643 | return runCount; 644 | }, 645 | true 646 | ); 647 | assert.strictEqual(runCount, 1, "has test with 'now' parameter should execute immediately"); 648 | 649 | assert.strictEqual(global.require.has('test2'), 2); 650 | assert.strictEqual(runCount, 2); 651 | assert.strictEqual(global.require.has('test3'), 1, 'Re-running has test should use cached value'); 652 | assert.strictEqual(runCount, 2); 653 | } 654 | }, 655 | 656 | nodeRequire() { 657 | assert.isFunction(global.require.nodeRequire, '"require.nodeRequire" should be a function'); 658 | assert.isNotNull( 659 | (global.require('events')).EventEmitter, 660 | '"require.nodeRequire" should load module' 661 | ); 662 | }, 663 | 664 | toAbsMid(this: any) { 665 | let dfd = this.async(DEFAULT_TIMEOUT); 666 | 667 | setErrorHandler(dfd); 668 | 669 | // Put the test in its own module so we can use context require 670 | global.define( 671 | 'common/a/toAbsMidTest', 672 | ['require'], 673 | dfd.callback(function(contextRequire: any) { 674 | assert.strictEqual(global.require.toAbsMid('mid'), 'mid'); 675 | assert.strictEqual(global.require.toAbsMid('./mid'), 'mid'); 676 | assert.strictEqual(global.require.toAbsMid('common/mid'), 'common/mid'); 677 | 678 | assert.strictEqual(contextRequire.toAbsMid('mid'), 'mid'); 679 | assert.strictEqual(contextRequire.toAbsMid('./mid'), 'common/a/mid'); 680 | assert.strictEqual(contextRequire.toAbsMid('../mid'), 'common/mid'); 681 | assert.strictEqual(contextRequire.toAbsMid('package/mid'), 'package/mid'); 682 | assert.strictEqual(contextRequire.toAbsMid('./package/mid'), 'common/a/package/mid'); 683 | assert.strictEqual(contextRequire.toAbsMid('../package/mid'), 'common/package/mid'); 684 | }) 685 | ); 686 | 687 | global.require.config({ 688 | baseUrl: './_build/tests' 689 | }); 690 | 691 | global.require(['common/a/toAbsMidTest'], () => {}); 692 | }, 693 | 694 | toUrl(this: any) { 695 | let dfd = this.async(DEFAULT_TIMEOUT); 696 | 697 | setErrorHandler(dfd); 698 | 699 | // Put the test in its own module so we can use context require 700 | global.define( 701 | 'common/a/toUrlTest', 702 | ['require'], 703 | dfd.callback(function(contextRequire: any) { 704 | assert.strictEqual(global.require.toUrl('mid'), '_build/tests/mid'); 705 | assert.strictEqual(global.require.toUrl('./mid'), '_build/tests/mid'); 706 | assert.strictEqual(global.require.toUrl('common/mid'), '_build/tests/common/mid'); 707 | 708 | assert.strictEqual(contextRequire.toUrl('mid'), '_build/tests/mid'); 709 | assert.strictEqual(contextRequire.toUrl('./mid'), '_build/tests/common/a/mid'); 710 | assert.strictEqual(contextRequire.toUrl('../mid'), '_build/tests/common/mid'); 711 | assert.strictEqual(contextRequire.toUrl('package/mid'), '_build/tests/package/mid'); 712 | assert.strictEqual(contextRequire.toUrl('./package/mid'), '_build/tests/common/a/package/mid'); 713 | assert.strictEqual(contextRequire.toUrl('../package/mid'), '_build/tests/common/package/mid'); 714 | }) 715 | ); 716 | 717 | global.require.config({ 718 | baseUrl: './_build/tests' 719 | }); 720 | 721 | global.require(['common/a/toUrlTest'], () => {}); 722 | }, 723 | 724 | undef(this: any) { 725 | let dfd = this.async(DEFAULT_TIMEOUT); 726 | 727 | (process)._events.uncaughtException = function(error: Error) { 728 | if (error.message.indexOf('common/app') === -1) { 729 | dfd.reject(error); 730 | } else { 731 | dfd.resolve(); 732 | } 733 | }; 734 | 735 | global.require.config({ 736 | packages: [ 737 | { 738 | name: 'common', 739 | location: './_build/tests/common' 740 | } 741 | ] 742 | }); 743 | 744 | global.require(['common/app'], function() { 745 | global.require.undef('common/app'); 746 | global.require('common/app'); 747 | dfd.reject('Loading undefined module should throw an error'); 748 | }); 749 | }, 750 | 751 | 'recurisve undef': { 752 | 'dependencies are unloaded'(this: any) { 753 | let dfd = this.async(DEFAULT_TIMEOUT); 754 | 755 | global.require.config({ 756 | packages: [ 757 | { 758 | name: 'recursive', 759 | location: './_build/tests/common/recursive' 760 | } 761 | ] 762 | }); 763 | 764 | function checkForUndef(mod: string): boolean { 765 | try { 766 | global.require(mod); 767 | } catch (error) { 768 | if (error.message.indexOf(mod) !== -1) { 769 | return true; 770 | } 771 | } 772 | return false; 773 | } 774 | 775 | global.require(['recursive/a'], function() { 776 | global.require.undef('recursive/a', true); 777 | const deps: string[] = [ 778 | 'recursive/a', 779 | 'recursive/b', 780 | 'recursive/c', 781 | 'recursive/d', 782 | 'recursive/e' 783 | ]; 784 | const passed: boolean = deps.every(function(mod: string) { 785 | return checkForUndef(mod); 786 | }); 787 | if (passed) { 788 | dfd.resolve(); 789 | } else { 790 | dfd.reject('not all dependencies were undefined'); 791 | } 792 | }); 793 | }, 794 | 795 | 'modules without dependencies work as expected'() { 796 | global.require.undef('invalid-module', true); 797 | } 798 | }, 799 | 800 | 'important modules are not undefined'(this: any) { 801 | let dfd = this.async(DEFAULT_TIMEOUT); 802 | 803 | global.define( 804 | 'undef-module', 805 | ['require', 'module', 'exports'], 806 | (require: any, module: any, exports: any) => { 807 | return { 808 | require, 809 | module, 810 | exports 811 | }; 812 | } 813 | ); 814 | 815 | global.require(['undef-module'], function() { 816 | global.require.undef('undef-module', true); 817 | 818 | global.define( 819 | 'undef-module-2', 820 | ['require', 'module', 'exports'], 821 | (require: any, module: any, exports: any) => { 822 | return { 823 | require, 824 | module, 825 | exports 826 | }; 827 | } 828 | ); 829 | 830 | assert.doesNotThrow(() => { 831 | global.require( 832 | ['undef-module-2'], 833 | dfd.callback((defs: any) => { 834 | assert.isTrue(defs.require !== undefined); 835 | assert.isTrue(defs.module !== undefined); 836 | assert.isTrue(defs.exports !== undefined); 837 | }) 838 | ); 839 | }); 840 | }); 841 | }, 842 | 843 | 'circular dependencies are required'(this: any) { 844 | let dfd = this.async(DEFAULT_TIMEOUT); 845 | 846 | global.require.config({ 847 | packages: [ 848 | { 849 | name: 'recursive', 850 | location: './_build/tests/common/recursive' 851 | } 852 | ] 853 | }); 854 | 855 | global.require( 856 | ['recursive/a'], 857 | dfd.callback(function(a: any) { 858 | assert.equal(a, 'a'); 859 | }) 860 | ); 861 | }, 862 | 863 | 'require.cache creates modules with only the cache call'(this: any) { 864 | let dfd = this.async(DEFAULT_TIMEOUT); 865 | 866 | global.require.config({ 867 | packages: [ 868 | { 869 | name: 'common', 870 | location: './_build/tests/common' 871 | } 872 | ] 873 | }); 874 | 875 | global.require.cache({ 876 | 'common/app'() { 877 | define([], () => { 878 | return 'mock'; 879 | }); 880 | } 881 | }); 882 | 883 | assert.doesNotThrow(() => { 884 | global.require( 885 | ['common/app'], 886 | dfd.callback((app: any) => { 887 | assert.strictEqual(app, 'mock', 'should return cache factory value'); 888 | }) 889 | ); 890 | }); 891 | }, 892 | 893 | 'cache injected module is properly undefined'(this: any) { 894 | let dfd = this.async(DEFAULT_TIMEOUT); 895 | 896 | global.require.config({ 897 | packages: [ 898 | { 899 | name: 'common', 900 | location: './_build/tests/common' 901 | } 902 | ] 903 | }); 904 | 905 | global.require.cache({ 906 | 'common/app'() { 907 | define([], () => { 908 | return 'mock'; 909 | }); 910 | } 911 | }); 912 | 913 | global.require( 914 | ['common/app'], 915 | dfd.callback(function(app: any) { 916 | assert.strictEqual(app, 'mock', 'should return cache factory value'); 917 | global.require.undef('common/app'); 918 | assert.throws( 919 | () => { 920 | global.require('common/app'); 921 | }, 922 | Error, 923 | 'Attempt to require unloaded module' 924 | ); 925 | }) 926 | ); 927 | }, 928 | 929 | plugin: { 930 | load(this: any) { 931 | const dfd = this.async(DEFAULT_TIMEOUT); 932 | 933 | global.require.config({ 934 | paths: { 935 | common: '_build/tests/common' 936 | } 937 | }); 938 | 939 | global.require( 940 | ['common/plugin!one'], 941 | dfd.callback(function(pluginOne: any) { 942 | assert.strictEqual(pluginOne, 'one', 'Plugin should return one'); 943 | }) 944 | ); 945 | }, 946 | 947 | config(this: any) { 948 | const dfd = this.async(DEFAULT_TIMEOUT); 949 | const paths: { [path: string]: string } = { 950 | common: '_build/tests/common' 951 | }; 952 | 953 | global.require.config({ paths }); 954 | 955 | global.require( 956 | ['common/pluginConfig!one'], 957 | dfd.callback(function(pluginConfig: any) { 958 | assert.property(pluginConfig, 'baseUrl', 'Base URL should be present'); 959 | assert.deepEqual( 960 | pluginConfig.paths, 961 | paths, 962 | 'Plugin should have received config param equal to require config' 963 | ); 964 | }) 965 | ); 966 | }, 967 | 968 | mergedConfig(this: any) { 969 | const dfd = this.async(DEFAULT_TIMEOUT); 970 | const paths: { [path: string]: string } = { 971 | common: '_build/tests/common' 972 | }; 973 | const map: DojoLoader.ModuleMap = { 974 | foo: 'bar' 975 | }; 976 | 977 | global.require.config({ paths }); 978 | global.require.config({ map }); 979 | 980 | global.require( 981 | ['common/pluginConfig!one'], 982 | dfd.callback(function(pluginConfig: any) { 983 | assert.deepEqual(pluginConfig.paths, paths, 'Paths should be equal'); 984 | assert.deepEqual(pluginConfig.map, map, 'Map should be equal'); 985 | }) 986 | ); 987 | }, 988 | 989 | relativePluginPaths(this: any) { 990 | const dfd = this.async(DEFAULT_TIMEOUT); 991 | 992 | global.require.config({ 993 | paths: { 994 | common: '_build/tests/common' 995 | } 996 | }); 997 | 998 | global.require( 999 | ['common/plugin!../../location'], 1000 | dfd.callback(function(pluginLocation: any) { 1001 | assert.strictEqual( 1002 | pluginLocation, 1003 | '../../location', 1004 | 'Plugin should return location it was passed correctly' 1005 | ); 1006 | }) 1007 | ); 1008 | } 1009 | } 1010 | } 1011 | }; 1012 | }); 1013 | -------------------------------------------------------------------------------- /tests/unit/simpleTest.js: -------------------------------------------------------------------------------- 1 | require('./_build/loader.js'); 2 | 3 | // this will be the return value from vm.runInContext 4 | x = 'y'; 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "inlineSources": true, 5 | "lib": [ 6 | "dom", 7 | "es5", 8 | "es2015.iterable", 9 | "es2015.promise", 10 | "es2015.symbol", 11 | "es2015.symbol.wellknown" 12 | ], 13 | "module": "commonjs", 14 | "moduleResolution": "node", 15 | "outDir": "_build/", 16 | "removeComments": false, 17 | "rootDir": ".", 18 | "sourceMap": true, 19 | "strict": true, 20 | "target": "es5", 21 | "types": [ "intern" ] 22 | }, 23 | "include": [ 24 | "./src/**/*.ts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "align": false, 4 | "ban": [], 5 | "class-name": true, 6 | "comment-format": [ true, "check-space" ], 7 | "curly": true, 8 | "eofline": true, 9 | "forin": false, 10 | "indent": [ true, "tabs" ], 11 | "interface-name": [ true, "never-prefix" ], 12 | "jsdoc-format": true, 13 | "label-position": true, 14 | "max-line-length": 120, 15 | "member-access": false, 16 | "member-ordering": false, 17 | "no-any": false, 18 | "no-arg": true, 19 | "no-bitwise": false, 20 | "no-consecutive-blank-lines": true, 21 | "no-console": false, 22 | "no-construct": false, 23 | "no-debugger": true, 24 | "no-duplicate-variable": true, 25 | "no-empty": false, 26 | "no-eval": true, 27 | "no-inferrable-types": [ true, "ignore-params" ], 28 | "no-shadowed-variable": false, 29 | "no-string-literal": false, 30 | "no-switch-case-fall-through": false, 31 | "no-trailing-whitespace": true, 32 | "no-unused-expression": false, 33 | "no-use-before-declare": false, 34 | "no-var-keyword": true, 35 | "no-var-requires": false, 36 | "object-literal-sort-keys": false, 37 | "one-line": [ true, "check-open-brace", "check-whitespace" ], 38 | "radix": true, 39 | "trailing-comma": [ true, { 40 | "multiline": "never", 41 | "singleline": "never" 42 | } ], 43 | "triple-equals": [ true, "allow-null-check" ], 44 | "typedef": false, 45 | "typedef-whitespace": [ true, { 46 | "call-signature": "nospace", 47 | "index-signature": "nospace", 48 | "parameter": "nospace", 49 | "property-declaration": "nospace", 50 | "variable-declaration": "nospace" 51 | }, { 52 | "call-signature": "onespace", 53 | "index-signature": "onespace", 54 | "parameter": "onespace", 55 | "property-declaration": "onespace", 56 | "variable-declaration": "onespace" 57 | } ], 58 | "variable-name": [ true, "check-format", "allow-leading-underscore", "ban-keywords" ] 59 | } 60 | } 61 | --------------------------------------------------------------------------------