Compare commits

...

51 Commits

Author SHA1 Message Date
Diana Lau c8241b2b35
Merge pull request #308 from achrinzafork/chore/update-lts
chore: update LTS status to End-of-Life
2021-02-09 10:48:13 -05:00
Rifa Achrinza afe57b5b04 chore: update LTS status to End-of-Life
see https://github.com/strongloop/loopback-next/issues/6957
2021-01-22 11:13:00 +08:00
Miroslav Bajtoš 56dcfaab6c
Merge pull request #305 from strongloop/feat/maintenance-lts
Update LTS status in README
2020-03-05 17:28:05 +01:00
Miroslav Bajtoš 51ec554632
Update LTS status in README 2020-03-05 13:41:27 +01:00
Agnes Lin f4313949c3
Merge pull request #302 from strongloop/copyright
chore: update copyrights year
2020-02-10 08:32:31 -05:00
Diana Lau 98883a877f chore: update copyrights year 2020-02-08 17:01:01 -05:00
Diana Lau 7a6021dc77
Merge pull request #301 from strongloop/fixbot
fix stale bot
2020-02-06 08:58:27 -05:00
Diana Lau f9d6d147bc fix stale bot 2020-02-03 14:18:55 -05:00
Nora 298aec304a
Merge pull request #300 from strongloop/chore/improve-issue-templates
chore: improve issue and PR templates
2019-11-21 10:31:47 -05:00
Nora 0043b9e27d
Merge pull request #299 from strongloop/fix-eslint
chore: fix eslint violations
2019-11-21 10:31:38 -05:00
Nora 3cbe0028a4 chore: improve issue and PR templates 2019-11-17 14:22:06 -05:00
Nora e9b108f9c6 chore: fix eslint violations 2019-11-17 14:19:25 -05:00
Miroslav Bajtoš 0bbe8335a4
Merge pull request #297 from strongloop/fix/ci
test: fix browserify-based tests
2019-10-07 10:38:13 +02:00
Miroslav Bajtoš c11ba18f73
test: fix browserify-based tests
Add `packageFilter` to handle buggy `async` browserify config.

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-03 17:06:12 +02:00
Miroslav Bajtoš 1fec4ea375
Merge pull request #298 from strongloop/drop-node6
Drop support for Node.js 6.x
2019-10-03 17:03:36 +02:00
Miroslav Bajtoš 974c63ccd5
Drop support for Node.js 6.x
It has reached end-of-life long time.

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-10-03 16:57:02 +02:00
Diana Lau f6b2f24b29
Merge pull request #296 from strongloop/stalebot
chore: add stalebot
2019-09-19 10:00:00 -04:00
Diana Lau b4d1f96494 chore: add stalebot 2019-09-19 09:36:49 -04:00
Diana Lau 6d8d9c92ce
Merge pull request #293 from strongloop/fix/publish-config
Tag 3.x versions as `latest` in npm registry
2019-06-25 09:54:04 -04:00
Miroslav Bajtoš 14050c199f
Tag 3.x versions as `latest` in npm registry
Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-06-25 08:38:07 +02:00
Diana Lau 59e46b3d91 3.3.1
* chore: update LTS status (Diana Lau)
 * chore: update copyrights years (Agnes Lin)
2019-06-24 11:22:44 -04:00
Diana Lau 8bb4368ca8
Merge pull request #292 from strongloop/lts
chore: update LTS status
2019-06-18 15:33:11 -04:00
Diana Lau a1d2954626 chore: update LTS status 2019-06-12 21:54:11 -04:00
Agnes Lin 837b8185f2
Merge pull request #290 from strongloop/copyrights
chore: update copyrights years
2019-05-07 10:29:23 -04:00
Agnes Lin ef39abf6eb chore: update copyrights years 2019-05-07 10:16:03 -04:00
Raymond Feng 8587dd6a19 3.3.0
* chore: upgrade deps to avoid npm audit warnings (Raymond Feng)
2019-03-28 14:28:27 -07:00
Raymond Feng 561cbd5bca
Merge pull request #289 from strongloop/upgrade-deps
chore: upgrade deps to avoid npm audit warnings
2019-03-28 14:27:11 -07:00
Raymond Feng 02da15cd3e chore: upgrade deps to avoid npm audit warnings 2019-03-26 11:14:56 -07:00
Miroslav Bajtoš 17ba74ed1c
3.2.1
* fix: set `app.booting` flag immediately (Miroslav Bajtoš)
 * fix: update lodash (jannyHou)
2019-03-22 16:34:33 +01:00
Miroslav Bajtoš e73b90ed97
Merge pull request #286 from strongloop/fix/booting-flag
fix: set `app.booting` flag immediately
2019-03-22 16:34:04 +01:00
Miroslav Bajtoš c10e8225bb
fix: set `app.booting` flag immediately
Before this change, `app.booting` was set by Application plugin as part
of regular phase invocation, which executes individual plugins in
subsequent turns of the event loop. As a result, `app.booting` was
initially `undefined` despite the fact that the booting process was
already in progress.

This patch moves manipulation of `app.booting` flag directly to
`Bootstrapper#run` method, to ensure it's set early enough and always
properly cleared at the end.
2019-03-22 13:57:25 +01:00
Janny 825411e6b4
Merge pull request #285 from strongloop/update/dependency-lodash
update lodash
2019-03-01 14:08:27 -05:00
jannyHou 9b77d8159a fix: update lodash 2019-03-01 12:32:47 -05:00
Miroslav Bajtoš fd3a381289
3.2.0
* README: update LTS status (Miroslav Bajtoš)
 * Add support for es6 modules for boot scripts (Walker)
2018-10-18 09:01:15 +02:00
Miroslav Bajtoš 3e7031c82e
Merge pull request #284 from strongloop/update-lts
README: update LTS status
2018-10-18 09:00:25 +02:00
Miroslav Bajtoš c278fe6705
README: update LTS status 2018-10-16 13:15:49 +02:00
Miroslav Bajtoš 0ace54cd9e
Merge pull request #280 from klarkc/master
Add support for es6 modules in boot scripts
2018-10-11 16:23:54 +02:00
Walker bfa874de63
Add support for es6 modules for boot scripts 2018-10-11 16:17:29 +02:00
Diana Lau b7a14e30e1 3.1.1
* update: dependency (jannyHou)
 * chore: update dependencies (Diana Lau)
 * [WebFM] cs/pl/ru translation (candytangnb)
 * chore: update license (Diana Lau)
 * CODEOWNERS: move @lehni to Alumni section (Miroslav Bajtoš)
 * Add support for ES6 style async boot scripts (Jürg Lehni)
2018-07-26 17:33:46 -04:00
Janny 2675771ec1
Merge pull request #283 from strongloop/update-dev
Update dev
2018-07-26 14:54:35 -04:00
jannyHou 14eeb4487d update: dependency 2018-07-26 14:16:16 -04:00
Diana Lau e89e353ab0
Merge pull request #282 from strongloop/update-dep
chore: update dependencies
2018-07-26 11:09:04 -04:00
Diana Lau d598c3738a chore: update dependencies 2018-07-25 21:59:39 -04:00
Taranveer Virk c4ab39c4e0
Merge pull request #281 from candytangnb/webfm-0629-000536-cs,pl,ru-translation
[WebFM] cs/pl/ru translation Check-in by YI TANG (tangyinb@cn.ibm.com)
2018-07-06 14:51:07 -04:00
candytangnb ded5bccb60 [WebFM] cs/pl/ru translation
cs/pl/ru translation check-in by YI TANG (tangyinb@cn.ibm.com) using
WebFM tool.
2018-06-29 00:05:36 -04:00
Miroslav Bajtoš 473e685a69
Merge pull request #253 from lehni/feature/async-boot-scripts-master
Add support for ES6 style async boot scripts
2017-12-11 10:35:22 +01:00
Diana Lau cdba5f0748
Merge pull request #274 from strongloop/license
chore: update license
2017-11-13 14:52:16 -05:00
Diana Lau 47ba28898a chore: update license 2017-11-10 18:02:24 -05:00
Miroslav Bajtoš a035aaa3ae Merge pull request #271 from strongloop/good-bye-lehni
CODEOWNERS: move @lehni to Alumni section
2017-10-19 10:53:05 +02:00
Miroslav Bajtoš c1cda7aefc
CODEOWNERS: move @lehni to Alumni section 2017-10-19 10:52:32 +02:00
Jürg Lehni 6e36f02005 Add support for ES6 style async boot scripts 2017-08-18 12:43:21 +02:00
70 changed files with 2722 additions and 1841 deletions

View File

@ -1,37 +0,0 @@
<!--
Questions:
https://groups.google.com/forum/#!forum/loopbackjs
https://gitter.im/strongloop/loopback
Immediate support:
https://strongloop.com/api-connect-faqs/
https://strongloop.com/node-js/subscription-plans/
-->
# Description/Steps to reproduce
<!--
If feature: A description of the feature
If bug: Steps to reproduce
-->
# Link to reproduction sandbox
<!--
Link to an app sandbox for reproduction
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
# Expected result
<!--
Also include actual results if bug
-->
# Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->

50
.github/ISSUE_TEMPLATE/Bug_report.md vendored Normal file
View File

@ -0,0 +1,50 @@
---
name: Bug report
about: Create a report to help us improve
labels: bug
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
HELP US HELP YOU, PLEASE
- Do a quick search to avoid duplicate issues
- Provide as much information as possible (reproduction sandbox, use case for features, etc.)
- Consider using a more suitable venue for questions such as Stack Overflow, Gitter, etc.
Please fill in the *entire* template below.
-->
## Steps to reproduce
<!-- Describe how to reproduce the issue -->
## Current Behavior
<!-- Describe the observed result -->
## Expected Behavior
<!-- Describe what did you expect instead, what is the desired outcome? -->
## Link to reproduction sandbox
<!--
See https://loopback.io/doc/en/contrib/Reporting-issues.html#loopback-3x-bugs
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
## Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->
## Related Issues
<!-- Did you find other bugs that looked similar? -->
_See [Reporting Issues](http://loopback.io/doc/en/contrib/Reporting-issues.html) for more tips on writing good issues_

View File

@ -0,0 +1,25 @@
---
name: Feature request
about: Suggest an idea for this project
labels: feature
---
## Suggestion
<!-- A summary of what you'd like to see added or changed -->
## Use Cases
<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->
## Examples
<!-- Show how this would be used and what the behavior would be -->
## Acceptance criteria
TBD - will be filled by the team.

27
.github/ISSUE_TEMPLATE/Question.md vendored Normal file
View File

@ -0,0 +1,27 @@
---
name: Question
about: The issue tracker is not for questions. Please use Stack Overflow or other resources for help.
labels: question
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
THE ISSUE TRACKER IS NOT FOR QUESTIONS.
DO NOT CREATE A NEW ISSUE TO ASK A QUESTION.
Please use one of the following resources for help:
**Questions**
- https://stackoverflow.com/tags/loopbackjs
- https://groups.google.com/forum/#!forum/loopbackjs
- https://gitter.im/strongloop/loopback
**Immediate support**
- https://strongloop.com/api-connect-faqs/
- https://strongloop.com/node-js/subscription-plans/
-->

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Report a security vulnerability
url: https://loopback.io/doc/en/contrib/Reporting-issues.html#security-issues
about: Do not report security vulnerabilities using GitHub issues. Please send an email to `reachsl@us.ibm.com` instead.
- name: Get help on StackOverflow
url: https://stackoverflow.com/tags/loopbackjs
about: Please ask and answer questions on StackOverflow.
- name: Join our mailing list
url: https://groups.google.com/forum/#!forum/loopbackjs
about: You can also post your question to our mailing list.

View File

@ -1,25 +1,18 @@
### Description
#### Related issues
<!--
Please use the following link syntaxes:
Please provide a high-level description of the changes made by your pull request.
- connect to #49 (to reference issues in the current repository)
- connect to strongloop/loopback#49 (to reference issues in another repository)
Include references to all related GitHub issues and other pull requests, for example:
Fixes #123
Implements #254
See also #23
-->
- connect to <link_to_referenced_issue>
## Checklist
### Checklist
<!--
- Please mark your choice with an "x" (i.e. [x], see
https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments)
- PR's without test coverage will be closed.
-->
👉 [Read and sign the CLA (Contributor License Agreement)](https://cla.strongloop.com/agreements/strongloop/loopback-boot) 👈
- [ ] `npm test` passes on your machine
- [ ] New tests added or existing tests modified to cover all changes
- [ ] Code conforms with the [style
guide](http://loopback.io/doc/en/contrib/style-guide.html)
- [ ] Code conforms with the [style guide](https://loopback.io/doc/en/contrib/style-guide-es6.html)
- [ ] Commit messages are following our [guidelines](https://loopback.io/doc/en/contrib/git-commit-messages.html)

24
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,24 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- critical
- p1
- major
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been closed due to continued inactivity. Thank you for your understanding.
If you believe this to be in error, please contact one of the code owners,
listed in the `CODEOWNERS` file at the top-level of this repository.

1
.npmrc Normal file
View File

@ -0,0 +1 @@
package-lock=false

View File

@ -1,7 +1,6 @@
sudo: false
language: node_js
node_js:
- "4"
- "6"
- "7"
- "8"
- "10"

View File

@ -1,3 +1,49 @@
2019-06-24, Version 3.3.1
=========================
* chore: update LTS status (Diana Lau)
* chore: update copyrights years (Agnes Lin)
2019-03-28, Version 3.3.0
=========================
* chore: upgrade deps to avoid npm audit warnings (Raymond Feng)
2019-03-22, Version 3.2.1
=========================
* fix: set `app.booting` flag immediately (Miroslav Bajtoš)
* fix: update lodash (jannyHou)
2018-10-18, Version 3.2.0
=========================
* README: update LTS status (Miroslav Bajtoš)
* Add support for es6 modules for boot scripts (Walker)
2018-07-26, Version 3.1.1
=========================
* update: dependency (jannyHou)
* chore: update dependencies (Diana Lau)
* [WebFM] cs/pl/ru translation (candytangnb)
* chore: update license (Diana Lau)
* CODEOWNERS: move @lehni to Alumni section (Miroslav Bajtoš)
* Add support for ES6 style async boot scripts (Jürg Lehni)
2017-10-13, Version 3.1.0
=========================

View File

@ -2,4 +2,10 @@
# Each line is a file pattern followed by one or more owners,
# the last matching pattern has the most precendence.
* @raymondfeng @lehni @zbarbuto
# Current maintainers
* @raymondfeng @zbarbuto
# Alumni
#
# @lehni

View File

@ -1,4 +1,4 @@
Copyright (c) IBM Corp. 2014,2016. All Rights Reserved.
Copyright (c) IBM Corp. 2014,2017. All Rights Reserved.
Node module: loopback-boot
This project is licensed under the MIT License, full text below.

View File

@ -1,11 +1,21 @@
# LoopBack Boot
**⚠️ LoopBack 3 has reached end of life. We are no longer accepting pull requests or providing
support for community users. The only exception is fixes for critical bugs and security
vulnerabilities provided as part of support for IBM API Connect customers. (See
[Module Long Term Support Policy](#module-long-term-support-policy) below.)**
We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as
soon as possible. Refer to our
[Migration Guide](https://loopback.io/doc/en/lb4/migration-overview.html)
for more information on how to upgrade.
## Overview
A convention-based bootstrapper for LoopBack applications.
For full documentation, see the official StrongLoop documentation: [Defining boot scripts](https://loopback.io/doc/en/lb2/Defining-boot-scripts) and [Creating a LoopBack application](https://loopback.io/doc/en/lb2/Creating-an-application).
## Overview
The loopback-boot module initializes (bootstraps) a LoopBack application. Specifically, it:
- Configures data-sources.
- Defines custom models
@ -46,6 +56,19 @@ app.listen();
See [API docs](http://apidocs.strongloop.com/loopback-boot/) for
complete API reference.
## Module Long Term Support Policy
This module adopts the [
Module Long Term Support (LTS)](http://github.com/CloudNativeJS/ModuleLTS) policy,
with the following End Of Life (EOL) dates:
| Version | Status | Published | EOL |
| ------- | --------------- | --------- | -------- |
| 3.x | End-of-Life | May 2017 | Dec 2020 |
| 2.x | End-of-Life | Jul 2014 | Apr 2019 |
Learn more about our LTS plan in [docs](https://loopback.io/doc/en/contrib/Long-term-support.html).
## License
This module is provided under dual MIT/StrongLoop license. See [LICENSE](LICENSE) for details.

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var Bootstrapper = require('./lib/bootstrapper');
const Bootstrapper = require('./lib/bootstrapper');
/**
* The browser version of `bootLoopBackApp`.
@ -26,18 +26,18 @@ var Bootstrapper = require('./lib/bootstrapper');
exports = module.exports = function bootBrowserApp(app, options, callback) {
// Only using options.id to identify the browserified bundle to load for
// this application. If no Id was provided, load the default bundle.
var moduleName = 'loopback-boot#instructions';
var appId = options && typeof options === 'object' && options.appId;
let moduleName = 'loopback-boot#instructions';
const appId = options && typeof options === 'object' && options.appId;
if (appId)
moduleName += '-' + appId;
// The name of the module containing instructions
// is hard-coded in lib/bundler
var instructions = require(moduleName);
const instructions = require(moduleName);
var bootstrapper = new Bootstrapper(options);
const bootstrapper = new Bootstrapper(options);
bootstrapper.phases = ['starting', 'start', 'started'];
var context = {
const context = {
app: app,
instructions: instructions,
};

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -6,11 +6,11 @@
'use strict';
// Strong globalize
var g = require('./lib/globalize');
const g = require('./lib/globalize');
var PluginBase = require('./lib/plugin-base');
var Bootstrapper = require('./lib/bootstrapper');
var addInstructionsToBrowserify = require('./lib/bundler');
const PluginBase = require('./lib/plugin-base');
const Bootstrapper = require('./lib/bootstrapper');
const addInstructionsToBrowserify = require('./lib/bundler');
/**
* Initialize an application from an options object or
@ -158,9 +158,9 @@ exports = module.exports = function bootLoopBackApp(app, options, callback) {
// backwards compatibility with loopback's app.boot
options.env = options.env || app.get('env');
var bootstrapper = new Bootstrapper(options);
const bootstrapper = new Bootstrapper(options);
var context = {
const context = {
bootstrapper: bootstrapper,
app: app,
};
@ -169,9 +169,9 @@ exports = module.exports = function bootLoopBackApp(app, options, callback) {
};
exports.compile = function(options, done) {
var bootstrapper = new Bootstrapper(options);
const bootstrapper = new Bootstrapper(options);
bootstrapper.phases = ['load', 'compile'];
var context = {};
const context = {};
return bootstrapper.run(context, done);
};
@ -199,9 +199,10 @@ exports.Bootstrapper = Bootstrapper;
exports.PluginBase = PluginBase;
exports.execute = function(app, instructions, done) {
var bootstrapper = new Bootstrapper(
{phases: ['starting', 'start', 'started']});
var context = {
const bootstrapper = new Bootstrapper(
{phases: ['starting', 'start', 'started']},
);
const context = {
app: app,
instructions: instructions,
};

17
intl/cs/messages.json Normal file
View File

@ -0,0 +1,17 @@
{
"1e5fea50eef843cbffd1d438494912c8": "Nelze vyřešit cestu \"{0}\"",
"34319676975b1abf107da7a056abb434": "Neplatný formát normalizace - \"{0}\"",
"3a7049e42006e8bc19e0f4fc8df63b6b": "Aplikace `app` je založena na nekompatibilní verzí Loopback {0}. Podporované verze: {1}",
"3f93b626dd9a1c33d67490f6e71018b5": "VAROVÁNÍ: Hlavní konfigurační soubor \"{0}{{.json}}\" chybí",
"4d052d84c8620730afd4a30832f11724": "Nelze konfigurovat neznámý model {0}",
"4ed668e9187650d898acf97707df445a": "Fáze {{phase}} \"{0}\" není definována v hlavní konfiguraci.",
"6447e6b342a2c51ab0bc53b3cbdf3742": "Konflikt řazení: Nelze přidat \"{0}\" za \"{1}\", protože již bylo uvedené opačné pořadí",
"70654dc6eb565613a33344efed3de998": "Nezdařilo se načíst zaváděcí skript: {0}\n{1}",
"7f7bdcadb75abfef1bd8a126d547dd6d": "{0} se neinterpretuje na platnou hodnotu, vráceno jako {1}. \"{2}\" musí být rozdělitelný v proměnné prostředí nebo {{app.get()}}.",
"91a742b7c3568cf6b6755741a70b3c52": "{{middleware}} \"{0}\" v {{phase}} \"{1}\" není definováno v hlavní konfiguraci.",
"a3aa22086ae4976cd013065c9a3ff81c": "Nelze použít {0}: ",
"be2cf2868ba54624fe38e9908dde5e9e": "Data v {{model-config.json}} jsou v nepodporovaném formátu {{1.x}}.",
"ec551b6f2fafd8d40af801ebe5bb09f6": "Vyřazení pokynů {{middleware}}, klient {{loopback}} nepodporuje {{middleware}}.",
"fdc23df1bd0fe55fe3faabcc89ff60f3": "Middleware \"{0}\" nelze nalézt: {1}"
}

17
intl/pl/messages.json Normal file
View File

@ -0,0 +1,17 @@
{
"1e5fea50eef843cbffd1d438494912c8": "Nie można rozstrzygnąć ścieżki \"{0}\"",
"34319676975b1abf107da7a056abb434": "Niepoprawny format normalizacji — \"{0}\"",
"3a7049e42006e8bc19e0f4fc8df63b6b": "Aplikacja jest obsługiwana przez niezgodną wersję aplikacji LoopBack {0}. Obsługiwane wersje: {1}",
"3f93b626dd9a1c33d67490f6e71018b5": "OSTRZEŻENIE: Brak głównego pliku konfiguracyjnego \"{0}{{.json}}\"",
"4d052d84c8620730afd4a30832f11724": "Nie można skonfigurować nieznanego modelu {0}",
"4ed668e9187650d898acf97707df445a": "Faza {{phase}} \"{0}\" nie została zdefiniowana w konfiguracji głównej.",
"6447e6b342a2c51ab0bc53b3cbdf3742": "Konflikt porządkowania: nie można dodać elementu \"{0}\" po elemencie \"{1}\", ponieważ została już określona odwrotna kolejność",
"70654dc6eb565613a33344efed3de998": "Nie powiodło się ładowanie skryptu startowego: {0}\n{1}",
"7f7bdcadb75abfef1bd8a126d547dd6d": "{0} nie umożliwia rozstrzygnięcia na poprawną wartość, zwrócono jako {1}. \"{2}\" musi umożliwiać rozstrzygnięcie w zmiennej środowiskowej lub przez metodę {{app.get()}}.",
"91a742b7c3568cf6b6755741a70b3c52": "Warstwa pośrednia {{middleware}} \"{0}\" w fazie {{phase}} \"{1}\" nie została zdefiniowana w konfiguracji głównej.",
"a3aa22086ae4976cd013065c9a3ff81c": "Nie można zastosować {0}: ",
"be2cf2868ba54624fe38e9908dde5e9e": "Dane w pliku {{model-config.json}} mają nieobsługiwany format {{1.x}}.",
"ec551b6f2fafd8d40af801ebe5bb09f6": "Odrzucanie instrukcji warstwy pośredniej {{middleware}}, klient {{loopback}} nie obsługuje warstwy pośredniej {{middleware}}.",
"fdc23df1bd0fe55fe3faabcc89ff60f3": "Warstwa pośrednia \"{0}\" nie została znaleziona: {1}"
}

17
intl/ru/messages.json Normal file
View File

@ -0,0 +1,17 @@
{
"1e5fea50eef843cbffd1d438494912c8": "Не удалось определить путь \"{0}\"",
"34319676975b1abf107da7a056abb434": "Недопустимый формат нормализации - \"{0}\"",
"3a7049e42006e8bc19e0f4fc8df63b6b": "Приложение `app` создано на основе несовместимой версии loopback {0}. Поддерживаемые версии: {1}",
"3f93b626dd9a1c33d67490f6e71018b5": "ПРЕДУПРЕЖДЕНИЕ: отсутствует главный файл конфигурации \"{0}{{.json}}\"",
"4d052d84c8620730afd4a30832f11724": "Не удается настроить неизвестную модель {0}",
"4ed668e9187650d898acf97707df445a": "Этап {{phase}} \"{0}\" не определен в главной конфигурации.",
"6447e6b342a2c51ab0bc53b3cbdf3742": "Конфликт упорядочения: не удается добавить \"{0}\" после \"{1}\", та как уже указан другой порядок",
"70654dc6eb565613a33344efed3de998": "Не удалось загрузить сценарий загрузки: {0}\n{1}",
"7f7bdcadb75abfef1bd8a126d547dd6d": "{0} не удается определить в допустимое значение, возвращено как {1}. \"{2}\" должен определяться как переменная среды или с помощью {{app.get()}}.",
"91a742b7c3568cf6b6755741a70b3c52": "{{middleware}} \"{0}\" на этапе {{phase}} \"{1}\"не определено в главной конфигурации.",
"a3aa22086ae4976cd013065c9a3ff81c": "Не удается применить {0}: ",
"be2cf2868ba54624fe38e9908dde5e9e": "Данные в {{model-config.json}} указаны в неподдерживаемом формате {{1.x}}.",
"ec551b6f2fafd8d40af801ebe5bb09f6": "Инструкции {{middleware}} отменяются, клиент {{loopback}} не поддерживает {{middleware}}.",
"fdc23df1bd0fe55fe3faabcc89ff60f3": "Не найдено промежуточное ПО \"{0}\": {1}"
}

73
lib/bootstrapper.js vendored
View File

@ -1,25 +1,25 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var _ = require('lodash');
var assert = require('assert');
var async = require('async');
var utils = require('./utils');
var path = require('path');
var pluginLoader = require('./plugin-loader');
var debug = require('debug')('loopback:boot:bootstrapper');
var Promise = require('bluebird');
var arrayToObject = require('./utils').arrayToObject;
const _ = require('lodash');
const assert = require('assert');
const async = require('async');
const utils = require('./utils');
const path = require('path');
const pluginLoader = require('./plugin-loader');
const debug = require('debug')('loopback:boot:bootstrapper');
const Promise = require('bluebird');
const arrayToObject = require('./utils').arrayToObject;
module.exports = Bootstrapper;
function createPromiseCallback() {
var cb;
var promise = new Promise(function(resolve, reject) {
let cb;
const promise = new Promise(function(resolve, reject) {
cb = function(err, data) {
if (err) return reject(err);
return resolve(data);
@ -29,22 +29,22 @@ function createPromiseCallback() {
return cb;
}
var builtinPlugins = [
const builtinPlugins = [
'application', 'datasource', 'model', 'mixin',
'middleware', 'component', 'boot-script', 'swagger',
];
var builtinPhases = [
const builtinPhases = [
'load', 'compile', 'starting', 'start', 'started',
];
function loadAndRegisterPlugins(bootstrapper, options) {
var loader = pluginLoader(options);
var loaderContext = {};
const loader = pluginLoader(options);
const loaderContext = {};
loader.load(loaderContext);
loader.compile(loaderContext);
for (var i in loaderContext.instructions.pluginScripts) {
for (const i in loaderContext.instructions.pluginScripts) {
bootstrapper.use('/boot/' + i, loaderContext.instructions.pluginScripts[i]);
}
}
@ -65,13 +65,13 @@ function Bootstrapper(options) {
// For setting properties without modifying the original object
options = Object.create(options);
var appRootDir = options.appRootDir = options.appRootDir || process.cwd();
var env = options.env || process.env.NODE_ENV || 'development';
var scriptExtensions = options.scriptExtensions ?
const appRootDir = options.appRootDir = options.appRootDir || process.cwd();
const env = options.env || process.env.NODE_ENV || 'development';
const scriptExtensions = options.scriptExtensions ?
arrayToObject(options.scriptExtensions) :
require.extensions;
var appConfigRootDir = options.appConfigRootDir || appRootDir;
const appConfigRootDir = options.appConfigRootDir || appRootDir;
options.rootDir = appConfigRootDir;
options.env = env;
@ -84,9 +84,9 @@ function Bootstrapper(options) {
assert(Array.isArray(this.plugins), 'Invalid plugins: ' +
this.builtinPlugins);
var self = this;
const self = this;
self.builtinPlugins.forEach(function(p) {
var factory = require('./plugins/' + p);
const factory = require('./plugins/' + p);
self.use('/boot/' + p, factory(options));
});
@ -103,7 +103,7 @@ function Bootstrapper(options) {
* @param {Function} handler
*/
Bootstrapper.prototype.use = function(path, handler) {
var plugin = {
const plugin = {
path: path,
handler: handler,
};
@ -135,7 +135,7 @@ Bootstrapper.prototype.getExtensions = function(path) {
}
return this.plugins.filter(function(p) {
if (p.path.indexOf(path) === -1) return false;
var name = p.path.substring(path.length);
const name = p.path.substring(path.length);
return name && name.indexOf('/') === -1;
});
};
@ -153,7 +153,7 @@ Bootstrapper.prototype.addPhases = function(phases) {
function pluginIteratorFactory(context, phase) {
return function executePluginPhase(plugin, done) {
var result;
let result;
if (typeof plugin.handler[phase] !== 'function') {
debug('Skipping %s.%s', plugin.handler.name, phase);
return done();
@ -190,23 +190,32 @@ Bootstrapper.prototype.run = function(context, done) {
if (!done) {
done = createPromiseCallback();
}
var options = this.options;
var appRootDir = options.appRootDir = options.appRootDir || process.cwd();
var env = options.env || process.env.NODE_ENV || 'development';
const options = this.options;
const appRootDir = options.appRootDir = options.appRootDir || process.cwd();
const env = options.env || process.env.NODE_ENV || 'development';
var appConfigRootDir = options.appConfigRootDir || appRootDir;
const appConfigRootDir = options.appConfigRootDir || appRootDir;
options.rootDir = appConfigRootDir;
options.env = env;
context = context || {};
var phases = context.phases || this.phases;
var bootPlugins = this.getExtensions('/boot');
const phases = context.phases || this.phases;
if (phases.includes('starting') || phases.includes('start')) {
context.app.booting = true;
}
const bootPlugins = this.getExtensions('/boot');
async.eachSeries(phases, function(phase, done) {
debug('Phase %s', phase);
async.eachSeries(bootPlugins, pluginIteratorFactory(context, phase), done);
}, function(err) {
if (phases.includes('started')) {
context.app.booting = false;
}
return done(err, context);
});
return done.promise;

View File

@ -1,15 +1,15 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var fs = require('fs');
var path = require('path');
var commondir = require('commondir');
var cloneDeep = require('lodash').cloneDeep;
var g = require('./globalize');
const fs = require('fs');
const path = require('path');
const commondir = require('commondir');
const cloneDeep = require('lodash').cloneDeep;
const g = require('./globalize');
/**
* Add boot instructions to a browserify bundler.
@ -27,8 +27,8 @@ module.exports = function addInstructionsToBrowserify(context, bundler) {
};
function addPlugins(bundler) {
var dir = path.join(__dirname, './plugins');
var files = fs.readdirSync(dir);
const dir = path.join(__dirname, './plugins');
const files = fs.readdirSync(dir);
files.forEach(function(f) {
bundler.require(path.join(dir, f),
{expose: './plugins/' + path.basename(f, '.js')});
@ -36,12 +36,12 @@ function addPlugins(bundler) {
}
function bundleOtherScripts(context, bundler) {
var list = context.instructions.bootScripts;
const list = context.instructions.bootScripts;
addScriptsToBundle('boot', list, bundler);
}
function bundlePluginScripts(context, bundler) {
var list = context.instructions.pluginScripts;
const list = context.instructions.pluginScripts;
addScriptsToBundle('plugins', list, bundler);
}
@ -58,11 +58,11 @@ function bundleComponentScripts(context, bundler) {
}
function bundleSourceFiles(context, type, bundler) {
var files = context.instructions[type]
const files = context.instructions[type]
.map(function(m) { return m.sourceFile; })
.filter(function(f) { return !!f; });
var instructionToFileMapping = context.instructions[type]
const instructionToFileMapping = context.instructions[type]
.map(function(m) { return files.indexOf(m.sourceFile); });
addScriptsToBundle(type, files, bundler);
@ -77,15 +77,16 @@ function bundleSourceFiles(context, type, bundler) {
function addScriptsToBundle(name, list, bundler) {
if (!list.length) return;
var root = commondir(list.map(path.dirname));
const root = commondir(list.map(path.dirname));
for (var ix in list) {
var filepath = list[ix];
for (const ix in list) {
const filepath = list[ix];
// Build a short unique id that does not expose too much
// information about the file system, but still preserves
// useful information about where is the file coming from.
var fileid = 'loopback-boot#' + name + '#' + path.relative(root, filepath);
const fileid =
'loopback-boot#' + name + '#' + path.relative(root, filepath);
// Add the file to the bundle.
bundler.require(filepath, {expose: fileid});
@ -97,18 +98,19 @@ function addScriptsToBundle(name, list, bundler) {
}
function bundleInstructions(context, bundler) {
var instructions = cloneDeep(context.instructions);
const instructions = cloneDeep(context.instructions);
var hasMiddleware = instructions.middleware.phases.length ||
const hasMiddleware = instructions.middleware.phases.length ||
instructions.middleware.middleware.length;
if (hasMiddleware) {
g.warn(
'Discarding {{middleware}} instructions,' +
' {{loopback}} client does not support {{middleware}}.');
' {{loopback}} client does not support {{middleware}}.',
);
}
delete instructions.middleware;
var instructionsString = JSON.stringify(instructions, null, 2);
const instructionsString = JSON.stringify(instructions, null, 2);
/* The following code does not work due to a bug in browserify
* https://github.com/substack/node-browserify/issues/771
@ -118,7 +120,7 @@ function bundleInstructions(context, bundler) {
b.require(instructionsStream, { expose: 'loopback-boot#instructions' });
*/
var instructionId = 'instructions';
let instructionId = 'instructions';
// Create an unique instruction identifier using the application ID.
// This is only useful when multiple loopback applications are being bundled
// together.
@ -127,10 +129,10 @@ function bundleInstructions(context, bundler) {
// Write the instructions to a file in our node_modules folder.
// The location should not really matter as long as it is .gitignore-ed
var instructionsFile = path.resolve(__dirname,
const instructionsFile = path.resolve(__dirname,
'..', 'generated-' + instructionId + '.json');
fs.writeFileSync(instructionsFile, instructionsString, 'utf-8');
var moduleName = 'loopback-boot#' + instructionId;
const moduleName = 'loopback-boot#' + instructionId;
bundler.require(instructionsFile, {expose: moduleName});
}

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path');
var SG = require('strong-globalize');
const path = require('path');
const SG = require('strong-globalize');
SG.SetRootDir(path.join(__dirname, '..'), {autonomousMsgLoading: 'all'});
module.exports = SG();

View File

@ -1,17 +1,17 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var fs = require('fs');
var path = require('path');
var debug = require('debug')('loopback:boot:plugin');
var assert = require('assert');
var _ = require('lodash');
var util = require('./utils');
var g = require('./globalize');
const fs = require('fs');
const path = require('path');
const debug = require('debug')('loopback:boot:plugin');
const assert = require('assert');
const _ = require('lodash');
const util = require('./utils');
const g = require('./globalize');
module.exports = PluginBase;
@ -26,11 +26,11 @@ PluginBase.prototype.getRootDir = function() {
};
PluginBase.prototype.load = function(context) {
var rootDir = this.getRootDir() || this.options.rootDir;
var env = this.options.env;
const rootDir = this.getRootDir() || this.options.rootDir;
const env = this.options.env;
assert(this.name, 'Plugin name must to be set');
debug('Root dir: %s, env: %s, artifact: %s', rootDir, env, this.artifact);
var config = {};
let config = {};
if (this.options[this.name]) {
// First check if options have the corresponding config object
debug('Artifact: %s is using provided config obj instead' +
@ -67,7 +67,7 @@ PluginBase.prototype.merge = function(target, config, keyPrefix) {
* @returns {Object}
*/
PluginBase.prototype.loadNamed = function(rootDir, env, name) {
var files = this.findConfigFiles(rootDir, env, name);
const files = this.findConfigFiles(rootDir, env, name);
debug('Looking in dir %s for %s configs', rootDir, this.name);
if (files.length) {
debug('found %s %s files: %j', env, name, files);
@ -75,8 +75,8 @@ PluginBase.prototype.loadNamed = function(rootDir, env, name) {
debug(' %s', f);
});
}
var configs = this._loadConfigFiles(files);
var merged = this._mergeConfigurations(configs);
const configs = this._loadConfigFiles(files);
const merged = this._mergeConfigurations(configs);
debug('merged %s %s configuration %j', env, name, merged);
@ -92,14 +92,14 @@ PluginBase.prototype.loadNamed = function(rootDir, env, name) {
* @returns {Array.<String>} Array of absolute file paths.
*/
PluginBase.prototype.findConfigFiles = function(rootDir, env, name, exts) {
var master = ifExists(name + '.json');
const master = ifExists(name + '.json');
if (!master && (ifExistsWithAnyExt(name + '.local') ||
ifExistsWithAnyExt(name + '.' + env))) {
g.warn('WARNING: Main config file "%s{{.json}}" is missing', name);
}
if (!master) return [];
var candidates = [
const candidates = [
master,
ifExistsWithAnyExt(name + '.local'),
ifExistsWithAnyExt(name + '.' + env),
@ -110,14 +110,14 @@ PluginBase.prototype.findConfigFiles = function(rootDir, env, name, exts) {
});
function ifExists(fileName) {
var filePath = path.resolve(rootDir, fileName);
const filePath = path.resolve(rootDir, fileName);
return util.fileExistsSync(filePath) ? filePath : undefined;
}
function ifExistsWithAnyExt(fileName) {
var extensions = exts || ['js', 'json'];
var file;
for (var i = 0, n = extensions.length; i < n; i++) {
const extensions = exts || ['js', 'json'];
let file;
for (let i = 0, n = extensions.length; i < n; i++) {
file = ifExists(fileName + '.' + extensions[i]);
if (file) {
return file;
@ -134,7 +134,7 @@ PluginBase.prototype.findConfigFiles = function(rootDir, env, name, exts) {
*/
PluginBase.prototype._loadConfigFiles = function(files) {
return files.map(function(f) {
var config = require(f);
let config = require(f);
config = _.cloneDeep(config);
Object.defineProperty(config, '_filename', {
enumerable: false,
@ -149,18 +149,18 @@ PluginBase.prototype._loadConfigFiles = function(files) {
* @param {Array.<Object>} configObjects
*/
PluginBase.prototype._mergeConfigurations = function(configObjects) {
var result = configObjects.shift() || {};
const result = configObjects.shift() || {};
while (configObjects.length) {
var next = configObjects.shift();
const next = configObjects.shift();
this.merge(result, next, next._filename);
}
return result;
};
PluginBase.prototype._mergeObjects = function(target, config, keyPrefix) {
for (var key in config) {
var fullKey = keyPrefix ? keyPrefix + '.' + key : key;
var err = this._mergeSingleItemOrProperty(target, config, key, fullKey);
for (const key in config) {
const fullKey = keyPrefix ? keyPrefix + '.' + key : key;
const err = this._mergeSingleItemOrProperty(target, config, key, fullKey);
if (err) throw err;
}
return null; // no error
@ -170,12 +170,12 @@ PluginBase.prototype._mergeNamedItems = function(arr1, arr2, key) {
assert(Array.isArray(arr1), 'invalid array: ' + arr1);
assert(Array.isArray(arr2), 'invalid array: ' + arr2);
key = key || 'name';
var result = [].concat(arr1);
for (var i = 0, n = arr2.length; i < n; i++) {
var item = arr2[i];
var found = false;
const result = [].concat(arr1);
for (let i = 0, n = arr2.length; i < n; i++) {
const item = arr2[i];
let found = false;
if (item[key]) {
for (var j = 0, k = result.length; j < k; j++) {
for (let j = 0, k = result.length; j < k; j++) {
if (result[j][key] === item[key]) {
this._mergeObjects(result[j], item);
found = true;
@ -192,8 +192,8 @@ PluginBase.prototype._mergeNamedItems = function(arr1, arr2, key) {
PluginBase.prototype._mergeSingleItemOrProperty =
function(target, config, key, fullKey) {
var origValue = target[key];
var newValue = config[key];
const origValue = target[key];
const newValue = config[key];
if (!hasCompatibleType(origValue, newValue)) {
return 'Cannot merge values of incompatible types for the option `' +
@ -219,9 +219,9 @@ PluginBase.prototype._mergeArrays = function(target, config, keyPrefix) {
}
// Use for(;;) to iterate over undefined items, for(in) would skip them.
for (var ix = 0; ix < target.length; ix++) {
var fullKey = keyPrefix + '[' + ix + ']';
var err = this._mergeSingleItemOrProperty(target, config, ix, fullKey);
for (let ix = 0; ix < target.length; ix++) {
const fullKey = keyPrefix + '[' + ix + ']';
const err = this._mergeSingleItemOrProperty(target, config, ix, fullKey);
if (err) return err;
}
@ -244,10 +244,10 @@ function hasCompatibleType(origValue, newValue) {
}
PluginBase.prototype.compile = function(context) {
var instructions;
let instructions;
if (typeof this.buildInstructions === 'function') {
var rootDir = this.options.rootDir;
var config = context.configurations[this.name] || {};
const rootDir = this.options.rootDir;
const config = context.configurations[this.name] || {};
instructions = this.buildInstructions(context, rootDir, config);
} else {
instructions = context.configurations[this.name];
@ -265,12 +265,12 @@ PluginBase.prototype.compile = function(context) {
return undefined;
};
var DYNAMIC_CONFIG_PARAM = /\$\{(\w+)\}$/;
const DYNAMIC_CONFIG_PARAM = /\$\{(\w+)\}$/;
function getConfigVariable(app, param, useEnvVars) {
var configVariable = param;
var match = configVariable.match(DYNAMIC_CONFIG_PARAM);
let configVariable = param;
const match = configVariable.match(DYNAMIC_CONFIG_PARAM);
if (match) {
var varName = match[1];
const varName = match[1];
if (useEnvVars && process.env[varName] !== undefined) {
debug('Dynamic Configuration: Resolved via process.env: %s as %s',
process.env[varName], param);
@ -278,7 +278,7 @@ function getConfigVariable(app, param, useEnvVars) {
} else if (app.get(varName) !== undefined) {
debug('Dynamic Configuration: Resolved via app.get(): %s as %s',
app.get(varName), param);
var appValue = app.get(varName);
const appValue = app.get(varName);
configVariable = appValue;
} else {
// previously it returns the original string such as "${restApiRoot}"
@ -287,7 +287,7 @@ function getConfigVariable(app, param, useEnvVars) {
configVariable = undefined;
g.warn('%s does not resolve to a valid value, returned as %s. ' +
'"%s" must be resolvable in Environment variable or by {{app.get()}}.',
param, configVariable, varName);
param, configVariable, varName);
debug('Dynamic Configuration: Cannot resolve variable for `%s`, ' +
'returned as %s', varName, configVariable);
}
@ -296,8 +296,8 @@ function getConfigVariable(app, param, useEnvVars) {
}
PluginBase.prototype.getUpdatedConfigObject = function(context, config, opts) {
var app = context.app;
var useEnvVars = opts && opts.useEnvVars;
const app = context.app;
const useEnvVars = opts && opts.useEnvVars;
function interpolateVariables(config) {
// config is a string and contains a config variable ('${var}')
@ -317,9 +317,9 @@ PluginBase.prototype.getUpdatedConfigObject = function(context, config, opts) {
return config;
// recurse into object props
var interpolated = {};
const interpolated = {};
Object.keys(config).forEach(function(configKey) {
var value = config[configKey];
const value = config[configKey];
if (Array.isArray(value)) {
interpolated[configKey] = value.map(interpolateVariables);
} else if (typeof value === 'string') {

View File

@ -1,17 +1,17 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var utils = require('./utils');
var path = require('path');
var async = require('async');
var debug = require('debug')('loopback:boot:plugin-loader');
var PluginBase = require('./plugin-base');
var _ = require('lodash');
const util = require('util');
const utils = require('./utils');
const path = require('path');
const async = require('async');
const debug = require('debug')('loopback:boot:plugin-loader');
const PluginBase = require('./plugin-base');
const _ = require('lodash');
module.exports = function(options) {
return new PluginScript(options);
@ -24,23 +24,23 @@ function PluginScript(options) {
util.inherits(PluginScript, PluginBase);
PluginScript.prototype.load = function(context) {
var options = this.options;
var appRootDir = options.rootDir;
const options = this.options;
const appRootDir = options.rootDir;
// require directories
var pluginDirs = options.pluginDirs || []; // precedence
let pluginDirs = options.pluginDirs || []; // precedence
pluginDirs = pluginDirs.concat(path.join(appRootDir, 'plugins'));
utils.resolveRelativePaths(pluginDirs, appRootDir);
var pluginScripts = options.pluginScripts || [];
let pluginScripts = options.pluginScripts || [];
utils.resolveRelativePaths(pluginScripts, appRootDir);
pluginDirs.forEach(function(dir) {
pluginScripts = pluginScripts.concat(
utils.findScripts(dir, options.scriptExtensions)
utils.findScripts(dir, options.scriptExtensions),
);
var envdir = dir + '/' + options.env;
const envdir = dir + '/' + options.env;
pluginScripts = pluginScripts.concat(
utils.findScripts(envdir, options.scriptExtensions)
utils.findScripts(envdir, options.scriptExtensions),
);
});
@ -51,15 +51,15 @@ PluginScript.prototype.load = function(context) {
};
PluginScript.prototype.compile = function(context) {
var pluginScripts = context.configurations.pluginScripts;
const pluginScripts = context.configurations.pluginScripts;
context.instructions = context.instructions || {};
var plugins = context.instructions.pluginScripts = {};
var self = this;
const plugins = context.instructions.pluginScripts = {};
const self = this;
pluginScripts.forEach(function(ps) {
debug('Loading %s', ps);
var factory = require(ps);
var handler = factory(self.options);
var name = handler.name || path.basename(ps, '.js');
const factory = require(ps);
const handler = factory(self.options);
const name = handler.name || path.basename(ps, '.js');
debug('Loaded plugin name: %s', name);
plugins[name] = handler;
});

View File

@ -1,15 +1,15 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var assert = require('assert');
var semver = require('semver');
var PluginBase = require('../plugin-base');
var g = require('../globalize');
const util = require('util');
const assert = require('assert');
const semver = require('semver');
const PluginBase = require('../plugin-base');
const g = require('../globalize');
module.exports = function(options) {
return new Application(options);
@ -22,19 +22,20 @@ function Application(options) {
util.inherits(Application, PluginBase);
function assertLoopBackVersion(app) {
var RANGE = '2.x || 3.x';
const RANGE = '2.x || 3.x';
var loopback = app.loopback;
const loopback = app.loopback;
// remove any pre-release tag from the version string,
// because semver has special treatment of pre-release versions,
// while loopback-boot treats pre-releases the same way as regular versions
var version = (loopback.version || '1.0.0').replace(/-.*$/, '');
const version = (loopback.version || '1.0.0').replace(/-.*$/, '');
if (!semver.satisfies(version, RANGE)) {
var msg = g.f(
const msg = g.f(
'The `app` is powered by an incompatible loopback version %s. ' +
'Supported versions: %s',
loopback.version || '(unknown)',
RANGE);
RANGE,
);
throw new Error(msg);
}
}
@ -46,7 +47,7 @@ function setEnv(app, env) {
function setHost(app, appConfig) {
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var host =
const host =
process.env.npm_config_host ||
process.env.OPENSHIFT_SLS_IP ||
process.env.OPENSHIFT_NODEJS_IP ||
@ -64,7 +65,7 @@ function setHost(app, appConfig) {
function setPort(app, appConfig) {
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var port = find([
const port = find([
process.env.npm_config_port,
process.env.OPENSHIFT_SLS_PORT,
process.env.OPENSHIFT_NODEJS_PORT,
@ -79,7 +80,7 @@ function setPort(app, appConfig) {
});
if (port !== undefined) {
var portType = typeof port;
const portType = typeof port;
assert(portType === 'string' || portType === 'number',
'app.port must be a string or number');
app.set('port', port);
@ -91,7 +92,7 @@ function find(array, predicate) {
}
function setApiRoot(app, appConfig) {
var restApiRoot =
const restApiRoot =
appConfig.restApiRoot ||
app.get('restApiRoot') ||
'/api';
@ -105,8 +106,8 @@ function setApiRoot(app, appConfig) {
}
function applyAppConfig(app, appConfig) {
for (var configKey in appConfig) {
var cur = app.get(configKey);
for (const configKey in appConfig) {
const cur = app.get(configKey);
if (cur === undefined || cur === null) {
app.set(configKey, appConfig[configKey]);
}
@ -114,11 +115,10 @@ function applyAppConfig(app, appConfig) {
}
Application.prototype.starting = function(context) {
var app = context.app;
app.booting = true;
const app = context.app;
assertLoopBackVersion(app);
var appConfig = context.instructions.application;
const appConfig = context.instructions.application;
setEnv(app, context.instructions.env || this.options.env);
setHost(app, appConfig);
setPort(app, appConfig);
@ -127,8 +127,7 @@ Application.prototype.starting = function(context) {
};
Application.prototype.started = function(context, done) {
var app = context.app;
app.booting = false;
const app = context.app;
process.nextTick(function() {
app.emit('booted');
done();

View File

@ -1,18 +1,18 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var utils = require('../utils');
var path = require('path');
var async = require('async');
var debug = require('debug')('loopback:boot:script');
var PluginBase = require('../plugin-base');
var _ = require('lodash');
var g = require('../globalize');
const util = require('util');
const utils = require('../utils');
const path = require('path');
const async = require('async');
const debug = require('debug')('loopback:boot:script');
const PluginBase = require('../plugin-base');
const _ = require('lodash');
const g = require('../globalize');
module.exports = function(options) {
return new Script(options);
@ -25,23 +25,23 @@ function Script(options) {
util.inherits(Script, PluginBase);
Script.prototype.load = function(context) {
var options = this.options;
var appRootDir = options.rootDir;
const options = this.options;
const appRootDir = options.rootDir;
// require directories
var bootDirs = options.bootDirs || []; // precedence
let bootDirs = options.bootDirs || []; // precedence
bootDirs = bootDirs.concat(path.join(appRootDir, 'boot'));
utils.resolveRelativePaths(bootDirs, appRootDir);
var bootScripts = options.bootScripts || [];
let bootScripts = options.bootScripts || [];
utils.resolveRelativePaths(bootScripts, appRootDir);
bootDirs.forEach(function(dir) {
bootScripts = bootScripts.concat(
utils.findScripts(dir, options.scriptExtensions)
utils.findScripts(dir, options.scriptExtensions),
);
var envdir = dir + '/' + options.env;
const envdir = dir + '/' + options.env;
bootScripts = bootScripts.concat(
utils.findScripts(envdir, options.scriptExtensions)
utils.findScripts(envdir, options.scriptExtensions),
);
});
@ -54,18 +54,19 @@ Script.prototype.load = function(context) {
};
Script.prototype.start = function(context, done) {
var app = context.app;
var instructions = context.instructions[this.name];
const app = context.app;
const instructions = context.instructions[this.name];
runScripts(app, instructions, done);
};
function runScripts(app, list, callback) {
list = list || [];
var functions = [];
const functions = [];
list.forEach(function(filepath) {
debug('Requiring script %s', filepath);
try {
var exports = require(filepath);
let exports = require(filepath);
if (exports.__esModule) exports = exports.default;
if (typeof exports === 'function') {
debug('Exported function detected %s', filepath);
functions.push({
@ -81,23 +82,24 @@ function runScripts(app, list, callback) {
async.eachSeries(functions, function(f, done) {
debug('Running script %s', f.path);
if (f.func.length >= 2) {
debug('Starting async function %s', f.path);
f.func(app, function(err) {
debug('Async function finished %s', f.path);
done(err);
});
} else {
debug('Starting sync function %s', f.path);
var error;
try {
f.func(app);
let cb = function(err) {
debug('Async function %s %s', err ? 'failed' : 'finished', f.path);
done(err);
// Make sure done() isn't called twice, e.g. if a script returns a
// thenable object and also calls the passed callback.
cb = function() {};
};
try {
const result = f.func(app, cb);
if (result && typeof result.then === 'function') {
result.then(function() { cb(); }, cb);
} else if (f.func.length < 2) {
debug('Sync function finished %s', f.path);
} catch (err) {
debug('Sync function failed %s', f.path, err);
error = err;
done();
}
done(error);
} catch (err) {
debug('Sync function failed %s', f.path, err);
done(err);
}
}, callback);
}

View File

@ -1,17 +1,17 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var debug = require('debug')('loopback:boot:component');
var PluginBase = require('../plugin-base');
const util = require('util');
const debug = require('debug')('loopback:boot:component');
const PluginBase = require('../plugin-base');
var utils = require('../utils');
const utils = require('../utils');
var resolveAppScriptPath = utils.resolveAppScriptPath;
const resolveAppScriptPath = utils.resolveAppScriptPath;
module.exports = function(options) {
return new Component(options);
@ -23,7 +23,7 @@ function Component(options) {
util.inherits(Component, PluginBase);
Component.prototype.getRootDir = function() {
Component.prototype.getRootDir = function() {
return this.options.componentRootDir || this.options.rootDir;
};
@ -40,11 +40,11 @@ Component.prototype.buildInstructions = function(context, rootDir, config) {
};
Component.prototype.start = function(context) {
var app = context.app;
var self = this;
const app = context.app;
const self = this;
context.instructions[this.name].forEach(function(data) {
debug('Configuring component %j', data.sourceFile);
var configFn = require(data.sourceFile);
const configFn = require(data.sourceFile);
data.config = self.getUpdatedConfigObject(context, data.config,
{useEnvVars: true});
configFn(app, data.config);

View File

@ -1,14 +1,14 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var utils = require('../utils');
var PluginBase = require('../plugin-base');
var debug = require('debug')('loopback:boot:datasource');
const util = require('util');
const utils = require('../utils');
const PluginBase = require('../plugin-base');
const debug = require('debug')('loopback:boot:datasource');
module.exports = function(options) {
return new DataSource(options);
@ -25,9 +25,9 @@ DataSource.prototype.getRootDir = function() {
};
DataSource.prototype.start = function(context) {
var app = context.app;
var self = this;
var lazyConnect = process.env.LB_LAZYCONNECT_DATASOURCES;
const app = context.app;
const self = this;
const lazyConnect = process.env.LB_LAZYCONNECT_DATASOURCES;
utils.forEachKeyedObject(context.instructions[this.name], function(key, obj) {
obj = self.getUpdatedConfigObject(context, obj, {useEnvVars: true});
debug('Registering data source %s %j', key, obj);

View File

@ -1,22 +1,22 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var assert = require('assert');
var path = require('path');
var _ = require('lodash');
var cloneDeepWith = _.cloneDeepWith;
var cloneDeep = _.cloneDeep;
var debug = require('debug')('loopback:boot:middleware');
var PluginBase = require('../plugin-base');
var utils = require('../utils');
var g = require('../globalize');
const util = require('util');
const assert = require('assert');
const path = require('path');
const _ = require('lodash');
const cloneDeepWith = _.cloneDeepWith;
const cloneDeep = _.cloneDeep;
const debug = require('debug')('loopback:boot:middleware');
const PluginBase = require('../plugin-base');
const utils = require('../utils');
const g = require('../globalize');
var resolveAppScriptPath = utils.resolveAppScriptPath;
const resolveAppScriptPath = utils.resolveAppScriptPath;
module.exports = function(options) {
return new Middleware(options);
@ -33,7 +33,7 @@ Middleware.prototype.getRootDir = function() {
};
Middleware.prototype.merge = function(target, config, fileName) {
var err, phase;
let err, phase;
for (phase in config) {
if (phase in target) {
err = this.mergePhaseConfig(target[phase], config[phase], phase);
@ -46,11 +46,11 @@ Middleware.prototype.merge = function(target, config, fileName) {
};
Middleware.prototype.mergePhaseConfig = function(target, config, phase) {
var err, mw;
let err, mw;
for (mw in config) {
if (mw in target) {
var targetMiddleware = target[mw];
var configMiddleware = config[mw];
const targetMiddleware = target[mw];
const configMiddleware = config[mw];
if (Array.isArray(targetMiddleware) && Array.isArray(configMiddleware)) {
// Both are arrays, combine them
target[mw] = this._mergeNamedItems(targetMiddleware, configMiddleware);
@ -83,18 +83,18 @@ Middleware.prototype.mergePhaseConfig = function(target, config, phase) {
};
Middleware.prototype.buildInstructions = function(context, rootDir, config) {
var phasesNames = Object.keys(config);
var middlewareList = [];
const phasesNames = Object.keys(config);
const middlewareList = [];
phasesNames.forEach(function(phase) {
var phaseConfig = config[phase];
const phaseConfig = config[phase];
Object.keys(phaseConfig).forEach(function(middleware) {
var allConfigs = phaseConfig[middleware];
let allConfigs = phaseConfig[middleware];
if (!Array.isArray(allConfigs))
allConfigs = [allConfigs];
allConfigs.forEach(function(config) {
var resolved = resolveMiddlewarePath(rootDir, middleware, config);
const resolved = resolveMiddlewarePath(rootDir, middleware, config);
// resolved.sourceFile will be false-y if an optional middleware
// is not resolvable.
// if a non-optional middleware is not resolvable, it will throw
@ -102,19 +102,19 @@ Middleware.prototype.buildInstructions = function(context, rootDir, config) {
if (!resolved.sourceFile) {
return g.log('Middleware "%s" not found: %s',
middleware,
resolved.optional
);
resolved.optional);
}
var middlewareConfig = cloneDeep(config);
const middlewareConfig = cloneDeep(config);
middlewareConfig.phase = phase;
if (middlewareConfig.params) {
middlewareConfig.params = resolveMiddlewareParams(
rootDir, middlewareConfig.params);
rootDir, middlewareConfig.params,
);
}
var item = {
const item = {
sourceFile: resolved.sourceFile,
config: middlewareConfig,
};
@ -126,7 +126,7 @@ Middleware.prototype.buildInstructions = function(context, rootDir, config) {
});
});
var flattenedPhaseNames = phasesNames
const flattenedPhaseNames = phasesNames
.map(function getBaseName(name) {
return name.replace(/:[^:]+$/, '');
})
@ -143,15 +143,15 @@ Middleware.prototype.buildInstructions = function(context, rootDir, config) {
};
function resolveMiddlewarePath(rootDir, middleware, config) {
var resolved = {
const resolved = {
optional: !!config.optional,
};
var segments = middleware.split('#');
var pathName = segments[0];
var fragment = segments[1];
var middlewarePath = pathName;
var opts = {
const segments = middleware.split('#');
let pathName = segments[0];
const fragment = segments[1];
const middlewarePath = pathName;
const opts = {
strict: true,
optional: !!config.optional,
};
@ -165,7 +165,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) {
pathName = path.resolve(rootDir, pathName);
}
var resolveOpts = _.extend(opts, {
const resolveOpts = _.extend(opts, {
// Workaround for strong-agent to allow probes to detect that
// strong-express-middleware was loaded: exclude the path to the
// module main file from the source file path.
@ -175,7 +175,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) {
// node_modules/strong-express-metrics/index.js
fullResolve: false,
});
var sourceFile = resolveAppScriptPath(rootDir, middlewarePath, resolveOpts);
const sourceFile = resolveAppScriptPath(rootDir, middlewarePath, resolveOpts);
if (!fragment) {
resolved.sourceFile = sourceFile;
@ -184,7 +184,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) {
// Try to require the module and check if <module>.<fragment> is a valid
// function
var m = require(sourceFile);
const m = require(sourceFile);
if (typeof m[fragment] === 'function') {
resolved.sourceFile = sourceFile;
return resolved;
@ -194,7 +194,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) {
* module/server/middleware/fragment
* module/middleware/fragment
*/
var candidates = [
const candidates = [
pathName + '/server/middleware/' + fragment,
pathName + '/middleware/' + fragment,
// TODO: [rfeng] Should we support the following flavors?
@ -202,7 +202,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) {
// pathName + '/' + fragment
];
var err, ix;
let err, ix;
for (ix in candidates) {
try {
resolved.sourceFile = resolveAppScriptPath(rootDir, candidates[ix], opts);
@ -217,7 +217,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) {
}
// Match values starting with `$!./` or `$!../`
var MIDDLEWARE_PATH_PARAM_REGEX = /^\$!(\.\/|\.\.\/)/;
const MIDDLEWARE_PATH_PARAM_REGEX = /^\$!(\.\/|\.\.\/)/;
function resolveMiddlewareParams(rootDir, params) {
return cloneDeepWith(params, function resolvePathParam(value) {
@ -230,20 +230,20 @@ function resolveMiddlewareParams(rootDir, params) {
}
Middleware.prototype.start = function(context) {
var self = this;
var app = context.app;
var instructions = context.instructions.middleware;
const self = this;
const app = context.app;
const instructions = context.instructions.middleware;
if (!instructions) {
// the browserified client does not support middleware
return;
}
// Phases can be empty
var phases = instructions.phases || [];
const phases = instructions.phases || [];
assert(Array.isArray(phases),
'Middleware phases must be an array');
var middleware = instructions.middleware;
const middleware = instructions.middleware;
assert(Array.isArray(middleware),
'Middleware must be an array');
@ -253,7 +253,7 @@ Middleware.prototype.start = function(context) {
middleware.forEach(function(data) {
debug('Configuring middleware %j%s', data.sourceFile,
data.fragment ? ('#' + data.fragment) : '');
var factory = require(data.sourceFile);
let factory = require(data.sourceFile);
if (data.fragment) {
factory = factory[data.fragment].bind(factory);
}

View File

@ -1,23 +1,23 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var fs = require('fs');
var path = require('path');
var PluginBase = require('../plugin-base');
var _ = require('lodash');
var debug = require('debug')('loopback:boot:mixin');
var utils = require('../utils');
var g = require('../globalize');
const util = require('util');
const fs = require('fs');
const path = require('path');
const PluginBase = require('../plugin-base');
const _ = require('lodash');
const debug = require('debug')('loopback:boot:mixin');
const utils = require('../utils');
const g = require('../globalize');
var tryResolveAppPath = utils.tryResolveAppPath;
var getExcludedExtensions = utils.getExcludedExtensions;
var findScripts = utils.findScripts;
var FILE_EXTENSION_JSON = utils.FILE_EXTENSION_JSON;
const tryResolveAppPath = utils.tryResolveAppPath;
const getExcludedExtensions = utils.getExcludedExtensions;
const findScripts = utils.findScripts;
const FILE_EXTENSION_JSON = utils.FILE_EXTENSION_JSON;
module.exports = function(options) {
return new Mixin(options);
@ -30,30 +30,31 @@ function Mixin(options) {
util.inherits(Mixin, PluginBase);
Mixin.prototype.buildInstructions = function(context, rootDir, config) {
var modelsMeta = context.configurations.mixins._meta || {};
var modelInstructions = context.instructions.models;
var mixinSources = this.options.mixinSources || modelsMeta.mixins ||
const modelsMeta = context.configurations.mixins._meta || {};
const modelInstructions = context.instructions.models;
const mixinSources = this.options.mixinSources || modelsMeta.mixins ||
['./mixins'];
var scriptExtensions = this.options.scriptExtensions || require.extensions;
const scriptExtensions = this.options.scriptExtensions || require.extensions;
var mixinInstructions = buildAllMixinInstructions(
rootDir, this.options, mixinSources, scriptExtensions, modelInstructions);
const mixinInstructions = buildAllMixinInstructions(
rootDir, this.options, mixinSources, scriptExtensions, modelInstructions,
);
return mixinInstructions;
};
function buildAllMixinInstructions(appRootDir, options, mixinSources,
scriptExtensions, modelInstructions) {
scriptExtensions, modelInstructions) {
// load mixins from `options.mixins`
var sourceFiles = options.mixins || [];
var mixinDirs = options.mixinDirs || [];
var instructionsFromMixins = loadMixins(sourceFiles, options.normalization);
let sourceFiles = options.mixins || [];
const mixinDirs = options.mixinDirs || [];
const instructionsFromMixins = loadMixins(sourceFiles, options.normalization);
// load mixins from `options.mixinDirs`
sourceFiles = findMixinDefinitions(appRootDir, mixinDirs, scriptExtensions);
if (sourceFiles === undefined) return;
var instructionsFromMixinDirs = loadMixins(sourceFiles,
options.normalization);
const instructionsFromMixinDirs = loadMixins(sourceFiles,
options.normalization);
/* If `mixinDirs` and `mixinSources` have any directories in common,
* then remove the common directories from `mixinSources` */
@ -61,31 +62,33 @@ function buildAllMixinInstructions(appRootDir, options, mixinSources,
// load mixins from `options.mixinSources`
sourceFiles = findMixinDefinitions(appRootDir, mixinSources,
scriptExtensions);
scriptExtensions);
if (sourceFiles === undefined) return;
var instructionsFromMixinSources = loadMixins(sourceFiles,
options.normalization);
let instructionsFromMixinSources = loadMixins(sourceFiles,
options.normalization);
// Fetch unique list of mixin names, used in models
var modelMixins = fetchMixinNamesUsedInModelInstructions(modelInstructions);
let modelMixins = fetchMixinNamesUsedInModelInstructions(modelInstructions);
modelMixins = _.uniq(modelMixins);
// Filter-in only mixins, that are used in models
instructionsFromMixinSources = filterMixinInstructionsUsingWhitelist(
instructionsFromMixinSources, modelMixins);
instructionsFromMixinSources, modelMixins,
);
var mixins = _.assign(
const mixins = _.assign(
instructionsFromMixins,
instructionsFromMixinDirs,
instructionsFromMixinSources);
instructionsFromMixinSources,
);
return _.values(mixins);
}
function findMixinDefinitions(appRootDir, sourceDirs, scriptExtensions) {
var files = [];
let files = [];
sourceDirs.forEach(function(dir) {
var path = tryResolveAppPath(appRootDir, dir);
const path = tryResolveAppPath(appRootDir, dir);
if (!path) {
debug('Skipping unknown module source dir %j', dir);
return;
@ -96,15 +99,15 @@ function findMixinDefinitions(appRootDir, sourceDirs, scriptExtensions) {
}
function loadMixins(sourceFiles, normalization) {
var mixinInstructions = {};
const mixinInstructions = {};
sourceFiles.forEach(function(filepath) {
var dir = path.dirname(filepath);
var ext = path.extname(filepath);
var name = path.basename(filepath, ext);
var metafile = path.join(dir, name + FILE_EXTENSION_JSON);
const dir = path.dirname(filepath);
const ext = path.extname(filepath);
let name = path.basename(filepath, ext);
const metafile = path.join(dir, name + FILE_EXTENSION_JSON);
name = normalizeMixinName(name, normalization);
var meta = {};
const meta = {};
meta.name = name;
if (utils.fileExistsSync(metafile)) {
// May overwrite name, not sourceFile
@ -126,10 +129,10 @@ function fetchMixinNamesUsedInModelInstructions(modelInstructions) {
}
function filterMixinInstructionsUsingWhitelist(instructions, includeMixins) {
var instructionKeys = Object.keys(instructions);
const instructionKeys = Object.keys(instructions);
includeMixins = _.intersection(instructionKeys, includeMixins);
var filteredInstructions = {};
const filteredInstructions = {};
instructionKeys.forEach(function(mixinName) {
if (includeMixins.indexOf(mixinName) !== -1) {
filteredInstructions[mixinName] = instructions[mixinName];
@ -165,7 +168,7 @@ function normalizeMixinName(str, normalization) {
return normalization(str);
}
var err = new Error(g.f('Invalid normalization format - "%s"',
const err = new Error(g.f('Invalid normalization format - "%s"',
normalization));
err.code = 'INVALID_NORMALIZATION_FORMAT';
throw err;
@ -173,18 +176,18 @@ function normalizeMixinName(str, normalization) {
}
Mixin.prototype.starting = function(context) {
var app = context.app;
var instructions = context.instructions.mixins;
const app = context.app;
const instructions = context.instructions.mixins;
var modelBuilder = (app.registry || app.loopback).modelBuilder;
var BaseClass = app.loopback.Model;
var mixins = instructions || [];
const modelBuilder = (app.registry || app.loopback).modelBuilder;
const BaseClass = app.loopback.Model;
const mixins = instructions || [];
if (!modelBuilder.mixins || !mixins.length) return;
mixins.forEach(function(obj) {
debug('Requiring mixin %s', obj.sourceFile);
var mixin = require(obj.sourceFile);
const mixin = require(obj.sourceFile);
if (typeof mixin === 'function' || mixin.prototype instanceof BaseClass) {
debug('Defining mixin %s', obj.name);

View File

@ -1,24 +1,24 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var assert = require('assert');
var util = require('util');
var PluginBase = require('../plugin-base');
var path = require('path');
var debug = require('debug')('loopback:boot:model');
var _ = require('lodash');
var toposort = require('toposort');
var utils = require('../utils');
const assert = require('assert');
const util = require('util');
const PluginBase = require('../plugin-base');
const path = require('path');
const debug = require('debug')('loopback:boot:model');
const _ = require('lodash');
const toposort = require('toposort');
const utils = require('../utils');
var tryReadDir = utils.tryReadDir;
var assertIsValidConfig = utils.assertIsValidConfig;
var tryResolveAppPath = utils.tryResolveAppPath;
var fixFileExtension = utils.fixFileExtension;
var g = require('../globalize');
const tryReadDir = utils.tryReadDir;
const assertIsValidConfig = utils.assertIsValidConfig;
const tryResolveAppPath = utils.tryResolveAppPath;
const fixFileExtension = utils.fixFileExtension;
const g = require('../globalize');
module.exports = function(options) {
return new Model(options);
@ -35,38 +35,42 @@ Model.prototype.getRootDir = function() {
};
Model.prototype.load = function(context) {
var config = PluginBase.prototype.load.apply(this, arguments);
const config = PluginBase.prototype.load.apply(this, arguments);
assertIsValidModelConfig(config);
return config;
};
Model.prototype.buildInstructions = function(context, rootDir, modelsConfig) {
var modelsMeta = modelsConfig._meta || {};
const modelsMeta = modelsConfig._meta || {};
delete modelsConfig._meta;
context.configurations.mixins._meta = modelsMeta;
var modelSources = this.options.modelSources || modelsMeta.sources ||
const modelSources = this.options.modelSources || modelsMeta.sources ||
['./models'];
var modelInstructions = buildAllModelInstructions(
const modelInstructions = buildAllModelInstructions(
rootDir, modelsConfig, modelSources, this.options.modelDefinitions,
this.options.scriptExtensions);
this.options.scriptExtensions,
);
return modelInstructions;
};
function buildAllModelInstructions(rootDir, modelsConfig, sources,
modelDefinitions, scriptExtensions) {
var registry = verifyModelDefinitions(rootDir, modelDefinitions,
scriptExtensions);
modelDefinitions, scriptExtensions) {
let registry = verifyModelDefinitions(rootDir, modelDefinitions,
scriptExtensions);
if (!registry) {
registry = findModelDefinitions(rootDir, sources, scriptExtensions);
}
var modelNamesToBuild = addAllBaseModels(registry, Object.keys(modelsConfig));
const modelNamesToBuild = addAllBaseModels(
registry,
Object.keys(modelsConfig),
);
var instructions = modelNamesToBuild
const instructions = modelNamesToBuild
.map(function createModelInstructions(name) {
var config = modelsConfig[name];
var definition = registry[name] || {};
const config = modelsConfig[name];
const definition = registry[name] || {};
debug('Using model "%s"\nConfiguration: %j\nDefinition %j',
name, config, definition.definition);
@ -83,20 +87,20 @@ function buildAllModelInstructions(rootDir, modelsConfig, sources,
}
function addAllBaseModels(registry, modelNames) {
var result = [];
var visited = {};
const result = [];
const visited = {};
while (modelNames.length) {
var name = modelNames.shift();
const name = modelNames.shift();
if (visited[name]) continue;
visited[name] = true;
result.push(name);
var definition = registry[name] && registry[name].definition;
const definition = registry[name] && registry[name].definition;
if (!definition) continue;
var base = getBaseModelName(definition);
const base = getBaseModelName(definition);
// ignore built-in models like User
if (!registry[base]) continue;
@ -117,14 +121,14 @@ function getBaseModelName(modelDefinition) {
function sortByInheritance(instructions) {
// create edges Base name -> Model name
var edges = instructions
const edges = instructions
.map(function(inst) {
return [getBaseModelName(inst.definition), inst.name];
});
var sortedNames = toposort(edges);
const sortedNames = toposort(edges);
var instructionsByModelName = {};
const instructionsByModelName = {};
instructions.forEach(function(inst) {
instructionsByModelName[inst.name] = inst;
});
@ -145,14 +149,15 @@ function verifyModelDefinitions(rootDir, modelDefinitions, scriptExtensions) {
return undefined;
}
var registry = {};
const registry = {};
modelDefinitions.forEach(function(definition, idx) {
if (definition.sourceFile) {
var fullPath = path.resolve(rootDir, definition.sourceFile);
const fullPath = path.resolve(rootDir, definition.sourceFile);
definition.sourceFile = fixFileExtension(
fullPath,
tryReadDir(path.dirname(fullPath)),
scriptExtensions);
scriptExtensions,
);
if (!definition.sourceFile) {
debug('Model source code not found: %s - %s', definition.sourceFile);
@ -166,11 +171,11 @@ function verifyModelDefinitions(rootDir, modelDefinitions, scriptExtensions) {
path.relative(rootDir, definition.sourceFile) :
'(no source file)');
var modelName = definition.definition.name;
const modelName = definition.definition.name;
if (!modelName) {
debug('Skipping model definition without Model name ' +
'(from options.modelDefinitions @ index %s)',
idx);
idx);
return;
}
registry[modelName] = definition;
@ -180,26 +185,26 @@ function verifyModelDefinitions(rootDir, modelDefinitions, scriptExtensions) {
}
function findModelDefinitions(rootDir, sources, scriptExtensions) {
var registry = {};
const registry = {};
sources.forEach(function(src) {
var srcDir = tryResolveAppPath(rootDir, src, {strict: false});
const srcDir = tryResolveAppPath(rootDir, src, {strict: false});
if (!srcDir) {
debug('Skipping unknown module source dir %j', src);
return;
}
var files = tryReadDir(srcDir);
const files = tryReadDir(srcDir);
files
.filter(function(f) {
return f[0] !== '_' && path.extname(f) === '.json';
})
.forEach(function(f) {
var fullPath = path.resolve(srcDir, f);
var entry = loadModelDefinition(rootDir, fullPath, files,
scriptExtensions);
var modelName = entry.definition.name;
const fullPath = path.resolve(srcDir, f);
const entry = loadModelDefinition(rootDir, fullPath, files,
scriptExtensions);
const modelName = entry.definition.name;
if (!modelName) {
debug('Skipping model definition without Model name: %s',
path.relative(srcDir, fullPath));
@ -213,12 +218,12 @@ function findModelDefinitions(rootDir, sources, scriptExtensions) {
}
function loadModelDefinition(rootDir, jsonFile, allFiles, scriptExtensions) {
var definition = require(jsonFile);
var basename = path.basename(jsonFile, path.extname(jsonFile));
const definition = require(jsonFile);
const basename = path.basename(jsonFile, path.extname(jsonFile));
definition.name = definition.name || _.upperFirst(_.camelCase(basename));
// find a matching file with a supported extension like `.js` or `.coffee`
var sourceFile = fixFileExtension(jsonFile, allFiles, scriptExtensions);
const sourceFile = fixFileExtension(jsonFile, allFiles, scriptExtensions);
if (sourceFile === undefined) {
debug('Model source code not found: %s', sourceFile);
@ -236,44 +241,46 @@ function loadModelDefinition(rootDir, jsonFile, allFiles, scriptExtensions) {
function assertIsValidModelConfig(config) {
assertIsValidConfig('model', config);
for (var name in config) {
var entry = config[name];
var options = entry.options || {};
var unsupported = entry.properties ||
for (const name in config) {
const entry = config[name];
const options = entry.options || {};
const unsupported = entry.properties ||
entry.base || options.base ||
entry.plural || options.plural;
if (unsupported) {
throw new Error(g.f(
'The data in {{model-config.json}} ' +
'is in the unsupported {{1.x}} format.'));
'is in the unsupported {{1.x}} format.',
));
}
}
}
// Regular expression to match built-in loopback models
var LOOPBACK_MODEL_REGEXP = new RegExp(
const LOOPBACK_MODEL_REGEXP = new RegExp(
['', 'node_modules', 'loopback', '[^\\/\\\\]+', 'models', '[^\\/\\\\]+\\.js$']
.join('\\' + path.sep));
.join('\\' + path.sep),
);
function isBuiltinLoopBackModel(app, data) {
// 1. Built-in models are exposed on the loopback object
if (!app.loopback[data.name]) return false;
// 2. Built-in models have a script file `loopback/{facet}/models/{name}.js`
var srcFile = data.sourceFile;
const srcFile = data.sourceFile;
return srcFile &&
LOOPBACK_MODEL_REGEXP.test(srcFile);
}
Model.prototype.start = function(context) {
var app = context.app;
var instructions = context.instructions[this.name];
const app = context.app;
const instructions = context.instructions[this.name];
var registry = app.registry || app.loopback;
const registry = app.registry || app.loopback;
instructions.forEach(function(data) {
var name = data.name;
var model;
const name = data.name;
let model;
if (!data.definition) {
model = registry.getModel(name);
@ -290,7 +297,7 @@ Model.prototype.start = function(context) {
model = registry.createModel(data.definition);
if (data.sourceFile) {
debug('Loading customization script %s', data.sourceFile);
var code = require(data.sourceFile);
const code = require(data.sourceFile);
if (typeof code === 'function') {
debug('Customizing model %s', name);
code(model);

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var util = require('util');
var PluginBase = require('../plugin-base');
const util = require('util');
const PluginBase = require('../plugin-base');
module.exports = function(options) {
return new Swagger(options);
@ -19,13 +19,13 @@ function Swagger(options) {
util.inherits(Swagger, PluginBase);
Swagger.prototype.start = function(context) {
var app = context.app;
var appConfig = context.instructions.application;
const app = context.app;
const appConfig = context.instructions.application;
// disable token requirement for swagger, if available
var swagger = app.remotes().exports.swagger;
const swagger = app.remotes().exports.swagger;
if (!swagger) return;
var requireTokenForSwagger = appConfig.swagger &&
const requireTokenForSwagger = appConfig.swagger &&
appConfig.swagger.requireToken;
swagger.requireToken = requireTokenForSwagger || false;
};

View File

@ -1,17 +1,17 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var debug = require('debug')('loopback:boot');
var path = require('path');
var Module = require('module');
var fs = require('fs');
var assert = require('assert');
var _ = require('lodash');
var g = require('./globalize');
const debug = require('debug')('loopback:boot');
const path = require('path');
const Module = require('module');
const fs = require('fs');
const assert = require('assert');
const _ = require('lodash');
const g = require('./globalize');
exports.arrayToObject = arrayToObject;
exports.tryReadDir = tryReadDir;
@ -26,7 +26,7 @@ exports.tryResolveAppPath = tryResolveAppPath;
exports.forEachKeyedObject = forEachKeyedObject;
exports.mergePhaseNameLists = mergePhaseNameLists;
var FILE_EXTENSION_JSON = exports.FILE_EXTENSION_JSON = '.json';
const FILE_EXTENSION_JSON = exports.FILE_EXTENSION_JSON = '.json';
/**
* Find all javascript files (except for those prefixed with _)
* and all directories.
@ -37,7 +37,7 @@ var FILE_EXTENSION_JSON = exports.FILE_EXTENSION_JSON = '.json';
function findScripts(dir, scriptExtensions) {
assert(dir, 'cannot require directory contents without directory name');
var files = tryReadDir(dir);
const files = tryReadDir(dir);
scriptExtensions = scriptExtensions || require.extensions;
// sort files in lowercase alpha for linux
@ -54,15 +54,15 @@ function findScripts(dir, scriptExtensions) {
}
});
var results = [];
const results = [];
files.forEach(function(filename) {
// ignore index.js and files prefixed with underscore
if (filename === 'index.js' || filename[0] === '_') {
return;
}
var filepath = path.resolve(path.join(dir, filename));
var stats = fs.statSync(filepath);
const filepath = path.resolve(path.join(dir, filename));
const stats = fs.statSync(filepath);
// only require files supported by specified extensions
if (stats.isFile()) {
@ -87,9 +87,13 @@ function tryReadDir() {
}
function resolveRelativePaths(relativePaths, appRootDir) {
var resolveOpts = {strict: false};
const resolveOpts = {strict: false};
relativePaths.forEach(function(relativePath, k) {
var resolvedPath = tryResolveAppPath(appRootDir, relativePath, resolveOpts);
const resolvedPath = tryResolveAppPath(
appRootDir,
relativePath,
resolveOpts,
);
if (resolvedPath !== undefined) {
relativePaths[k] = resolvedPath;
} else {
@ -102,7 +106,7 @@ function getExcludedExtensions() {
return {
'.json': '.json',
'.node': 'node',
/**
/**
* This is a temporary workaround for #246
* See discussion here for full description of the underlying issue
* https://github.com/strongloop/loopback-boot/pull/245#issuecomment-311052798
@ -121,28 +125,28 @@ function arrayToObject(array) {
function isPreferredExtension(filename, includeExtensions) {
assert(!!includeExtensions, '"includeExtensions" argument is required');
var ext = path.extname(filename);
const ext = path.extname(filename);
return (ext in includeExtensions) && !(ext in getExcludedExtensions());
}
function fixFileExtension(filepath, files, scriptExtensions) {
var results = [];
var otherFile;
const results = [];
let otherFile;
/* Prefer coffee scripts over json */
if (scriptExtensions && isPreferredExtension(filepath, scriptExtensions)) {
return filepath;
}
var basename = path.basename(filepath, FILE_EXTENSION_JSON);
var sourceDir = path.dirname(filepath);
const basename = path.basename(filepath, FILE_EXTENSION_JSON);
const sourceDir = path.dirname(filepath);
files.forEach(function(f) {
otherFile = path.resolve(sourceDir, f);
var stats = fs.statSync(otherFile);
const stats = fs.statSync(otherFile);
if (stats.isFile()) {
var otherFileExtension = path.extname(f);
const otherFileExtension = path.extname(f);
if (!(otherFileExtension in getExcludedExtensions()) &&
path.basename(f, otherFileExtension) == basename) {
@ -156,9 +160,9 @@ function fixFileExtension(filepath, files, scriptExtensions) {
}
function resolveAppPath(rootDir, relativePath, resolveOptions) {
var resolvedPath = tryResolveAppPath(rootDir, relativePath, resolveOptions);
const resolvedPath = tryResolveAppPath(rootDir, relativePath, resolveOptions);
if (resolvedPath === undefined && !resolveOptions.optional) {
var err = new Error(g.f('Cannot resolve path "%s"', relativePath));
const err = new Error(g.f('Cannot resolve path "%s"', relativePath));
err.code = 'PATH_NOT_FOUND';
throw err;
}
@ -166,19 +170,19 @@ function resolveAppPath(rootDir, relativePath, resolveOptions) {
}
function resolveAppScriptPath(rootDir, relativePath, resolveOptions) {
var resolvedPath = resolveAppPath(rootDir, relativePath, resolveOptions);
const resolvedPath = resolveAppPath(rootDir, relativePath, resolveOptions);
if (!resolvedPath) {
return false;
}
var sourceDir = path.dirname(resolvedPath);
var files = tryReadDir(sourceDir);
var fixedFile = fixFileExtension(resolvedPath, files);
const sourceDir = path.dirname(resolvedPath);
const files = tryReadDir(sourceDir);
const fixedFile = fixFileExtension(resolvedPath, files);
return (fixedFile === undefined ? resolvedPath : fixedFile);
}
function tryResolveAppPath(rootDir, relativePath, resolveOptions) {
var fullPath;
var start = relativePath.substring(0, 2);
let fullPath;
const start = relativePath.substring(0, 2);
/* In order to retain backward compatibility, we need to support
* two ways how to treat values that are not relative nor absolute
@ -189,7 +193,7 @@ function tryResolveAppPath(rootDir, relativePath, resolveOptions) {
*/
resolveOptions = resolveOptions || {strict: true};
var isModuleRelative = false;
let isModuleRelative = false;
if (relativePath[0] === '/') {
fullPath = relativePath;
} else if (start === './' || start === '..') {
@ -222,17 +226,17 @@ function tryResolveAppPath(rootDir, relativePath, resolveOptions) {
// [ env.NODE_PATH values, $HOME/.node_modules, etc. ]
// Module._nodeModulePaths(rootDir) returns a list of paths like
// [ rootDir/node_modules, rootDir/../node_modules, etc. ]
var modulePaths = Module.globalPaths
const modulePaths = Module.globalPaths
.concat(Module._nodeModulePaths(rootDir));
fullPath = modulePaths
.map(function(candidateDir) {
var absPath = path.join(candidateDir, relativePath);
const absPath = path.join(candidateDir, relativePath);
try {
// NOTE(bajtos) We need to create a proper String object here,
// otherwise we can't attach additional properties to it
/* jshint -W053 */
var filePath = new String(require.resolve(absPath));
const filePath = new String(require.resolve(absPath));
filePath.unresolvedPath = absPath;
return filePath;
} catch (err) {
@ -310,8 +314,8 @@ function forEachKeyedObject(obj, fn) {
function mergePhaseNameLists(currentNames, namesToMerge) {
if (!namesToMerge.length) return currentNames.slice();
var targetArray = currentNames.slice();
var targetIx = targetArray.indexOf(namesToMerge[0]);
const targetArray = currentNames.slice();
let targetIx = targetArray.indexOf(namesToMerge[0]);
if (targetIx === -1) {
// the first new item does not match any existing one
@ -321,21 +325,21 @@ function mergePhaseNameLists(currentNames, namesToMerge) {
}
// merge (zip) two arrays
for (var sourceIx = 1; sourceIx < namesToMerge.length; sourceIx++) {
var valueToAdd = namesToMerge[sourceIx];
var previousValue = namesToMerge[sourceIx - 1];
var existingIx = targetArray.indexOf(valueToAdd, targetIx);
for (let sourceIx = 1; sourceIx < namesToMerge.length; sourceIx++) {
const valueToAdd = namesToMerge[sourceIx];
const previousValue = namesToMerge[sourceIx - 1];
const existingIx = targetArray.indexOf(valueToAdd, targetIx);
if (existingIx === -1) {
// A new phase - try to add it after the last one,
// unless it was already registered
if (targetArray.indexOf(valueToAdd) !== -1) {
var errMsg = g.f('Ordering conflict: cannot add "%s' +
const errMsg = g.f('Ordering conflict: cannot add "%s' +
'" after "%s", because the opposite order was ' +
' already specified', valueToAdd, previousValue);
throw new Error(errMsg);
}
var previousIx = targetArray.indexOf(previousValue);
const previousIx = targetArray.indexOf(previousValue);
targetArray.splice(previousIx + 1, 0, valueToAdd);
} else {
// An existing phase - move the pointer

View File

@ -1,9 +1,6 @@
{
"name": "loopback-boot",
"version": "3.1.0",
"publishConfig": {
"tag": "next"
},
"version": "3.3.1",
"description": "Convention-based bootstrapper for LoopBack applications",
"keywords": [
"StrongLoop",
@ -16,37 +13,39 @@
"url": "https://github.com/strongloop/loopback-boot"
},
"engines": {
"node": ">=4.0.0"
"node": ">=8"
},
"main": "index.js",
"browser": "browser.js",
"scripts": {
"test": "mocha",
"posttest": "npm run lint",
"lint": "eslint ."
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"license": "MIT",
"dependencies": {
"async": "^2.4.0",
"bluebird": "^3.4.0",
"bluebird": "^3.5.3",
"commondir": "^1.0.1",
"debug": "^2.2.0",
"lodash": "^4.13.1",
"debug": "^4.1.1",
"lodash": "^4.17.11",
"semver": "^5.1.0",
"strong-globalize": "^3.1.0",
"toposort": "^1.0.0"
"strong-globalize": "^4.1.1",
"toposort": "^2.0.2"
},
"devDependencies": {
"browserify": "^4.2.3",
"chai": "^3.5.0",
"coffee-script": "^1.10.0",
"coffeeify": "^2.0.1",
"dirty-chai": "^1.2.2",
"eslint": "^3.19.0",
"eslint-config-loopback": "^8.0.0",
"fs-extra": "^3.0.1",
"browserify": "^16.2.3",
"chai": "^4.2.0",
"coffeeify": "^3.0.1",
"coffeescript": "^2.3.1",
"dirty-chai": "^2.0.1",
"eslint": "^6.6.0",
"eslint-config-loopback": "^13.1.0",
"fs-extra": "^7.0.1",
"loopback": "^3.0.0",
"mocha": "^3.3.0",
"supertest": "^3.0.0"
}
"mocha": "^5.2.0",
"supertest": "^4.0.2"
},
"author": "IBM Corp."
}

40
test/acceptance.test.js Normal file
View File

@ -0,0 +1,40 @@
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
const path = require('path');
const loopback = require('loopback');
const chai = require('chai');
const dirtyChai = require('dirty-chai');
const expect = chai.expect;
chai.use(dirtyChai);
const bootLoopBackApp = require('..');
describe('bootLoopBackApp', function() {
let app;
beforeEach(function() {
app = loopback();
});
it('sets app.booting immediately', function() {
const appDir = path.join(__dirname, './fixtures/empty-app');
// Start the bootstrapper
const promise = bootLoopBackApp(app, appDir);
// Still in the original turn of the event loop,
// verify that the app is signalling "boot in progress"
expect(app.booting).to.equal(true);
// Wait for bootstrapper to finish
return promise.then(() => {
// Verify that app is signalling "boot has finished"
expect(app.booting).to.equal(false);
});
});
});

View File

@ -1,38 +1,43 @@
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path');
var loopback = require('loopback');
const path = require('path');
const loopback = require('loopback');
var chai = require('chai');
var dirtyChai = require('dirty-chai');
var expect = chai.expect;
const chai = require('chai');
const dirtyChai = require('dirty-chai');
const expect = chai.expect;
chai.use(dirtyChai);
var Bootstrapper = require('../lib/bootstrapper');
const Bootstrapper = require('../lib/bootstrapper');
describe('Bootstrapper', function() {
var app;
let app;
beforeEach(function() {
app = loopback();
process.bootFlags = [];
});
it('should honor options.phases', function(done) {
var options = {
const options = {
app: app,
appRootDir: path.join(__dirname, './fixtures/simple-app'),
phases: ['load'],
};
var bootstrapper = new Bootstrapper(options);
const bootstrapper = new Bootstrapper(options);
var context = {
const context = {
app: app,
};
bootstrapper.run(context, function(err) {
if (err) return done(err);
var configs = context.configurations;
const configs = context.configurations;
expect(configs.application, 'application').to.be.an('object');
expect(configs.bootScripts, 'bootScripts').to.be.an('array');
expect(configs.middleware, 'middleware').to.be.an('object');
@ -45,22 +50,22 @@ describe('Bootstrapper', function() {
});
it('should honor options.plugins', function(done) {
var options = {
const options = {
app: app,
appRootDir: path.join(__dirname, './fixtures/simple-app'),
plugins: ['application', 'boot-script'],
};
var bootstrapper = new Bootstrapper(options);
const bootstrapper = new Bootstrapper(options);
var context = {
const context = {
app: app,
};
bootstrapper.run(context, function(err) {
if (err) return done(err);
var configs = context.configurations;
var instructions = context.instructions;
const configs = context.configurations;
const instructions = context.instructions;
expect(configs.application, 'application').to.be.an('object');
expect(configs.middleware, 'middleware').to.be.undefined();
expect(configs.models, 'models').to.be.undefined();
@ -68,40 +73,48 @@ describe('Bootstrapper', function() {
expect(instructions.application, 'application').to.be.an('object');
expect(instructions.tracker, 'instruction: tracker').to.eql('compile');
expect(context.executions.tracker, 'execution: tracker').to.eql('start');
expect(process.bootFlags, 'process: bootFlags').to.eql(['barLoaded',
expect(process.bootFlags, 'process: bootFlags').to.eql([
'barLoaded',
'barSyncLoaded',
'fooLoaded',
'promiseLoaded',
'thenableLoaded',
'barStarted',
'barFinished',
'barSyncExecuted',
'promiseStarted',
'promiseFinished',
'thenableStarted',
'thenableFinished',
'umdLoaded',
]);
done();
});
});
it('searches boot file extensions specified in options.scriptExtensions',
function(done) {
var options = {
app: app,
appRootDir: path.join(__dirname, './fixtures/simple-app'),
scriptExtensions: ['.customjs', '.customjs2'],
};
function(done) {
const options = {
app: app,
appRootDir: path.join(__dirname, './fixtures/simple-app'),
scriptExtensions: ['.customjs', '.customjs2'],
};
var bootstrapper = new Bootstrapper(options);
const bootstrapper = new Bootstrapper(options);
var context = {
app: app,
};
const context = {
app: app,
};
bootstrapper.run(context, function(err) {
if (err) return done(err);
expect(process.bootFlags, 'process: bootFlags').to.eql([
'customjs',
'customjs2',
]);
done();
bootstrapper.run(context, function(err) {
if (err) return done(err);
expect(process.bootFlags, 'process: bootFlags').to.eql([
'customjs',
'customjs2',
]);
done();
});
});
});
afterEach(function() {
delete process.bootFlags;

View File

@ -1,21 +1,22 @@
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('../');
var async = require('async');
var exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox;
var fs = require('fs');
var path = require('path');
var expect = require('chai').expect;
var browserify = require('browserify');
var sandbox = require('./helpers/sandbox');
var vm = require('vm');
var createBrowserLikeContext = require('./helpers/browser').createContext;
var printContextLogs = require('./helpers/browser').printContextLogs;
const boot = require('../');
const async = require('async');
const exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox;
const packageFilter = require('./helpers/browserify').packageFilter;
const fs = require('fs');
const path = require('path');
const expect = require('chai').expect;
const browserify = require('browserify');
const sandbox = require('./helpers/sandbox');
const vm = require('vm');
const createBrowserLikeContext = require('./helpers/browser').createContext;
const printContextLogs = require('./helpers/browser').printContextLogs;
describe('browser support for multiple apps', function() {
this.timeout(60000); // 60s to give browserify enough time to finish
@ -23,10 +24,10 @@ describe('browser support for multiple apps', function() {
beforeEach(sandbox.reset);
it('has API for bundling and booting multiple apps', function(done) {
var app1Dir = path.resolve(__dirname, './fixtures/browser-app');
var app2Dir = path.resolve(__dirname, './fixtures/browser-app-2');
const app1Dir = path.resolve(__dirname, './fixtures/browser-app');
const app2Dir = path.resolve(__dirname, './fixtures/browser-app-2');
var apps = [
const apps = [
{
appDir: app1Dir,
appFile: './app.js',
@ -43,9 +44,9 @@ describe('browser support for multiple apps', function() {
browserifyTestApps(apps, function(err, bundlePath) {
if (err) return done(err);
var bundledApps = executeBundledApps(bundlePath, apps, function(err) {
var app1 = bundledApps.defaultApp;
var app2 = bundledApps.browserApp2;
const bundledApps = executeBundledApps(bundlePath, apps, function(err) {
const app1 = bundledApps.defaultApp;
const app2 = bundledApps.browserApp2;
expect(app1.settings).to.have.property('custom-key', 'custom-value');
expect(Object.keys(app1.models)).to.include('Customer');
@ -63,22 +64,23 @@ describe('browser support for multiple apps', function() {
});
function browserifyTestApps(apps, next) {
var b = browserify({
const b = browserify({
debug: true,
basedir: path.resolve(__dirname, './fixtures'),
packageFilter,
});
var bundles = [];
for (var i in apps) {
var appDir = apps[i].appDir;
var appFile = apps[i].appFile;
var moduleName = apps[i].moduleName;
var appId = apps[i].appId;
const bundles = [];
for (const i in apps) {
const appDir = apps[i].appDir;
let appFile = apps[i].appFile;
const moduleName = apps[i].moduleName;
const appId = apps[i].appId;
appFile = path.join(appDir, appFile);
b.require(appFile, {expose: moduleName});
var opts = appDir;
let opts = appDir;
if (appId) {
opts = {
appId: appId,
@ -95,21 +97,21 @@ function browserifyTestApps(apps, next) {
}
function executeBundledApps(bundlePath, apps, done) {
var code = fs.readFileSync(bundlePath);
var context = createBrowserLikeContext();
const code = fs.readFileSync(bundlePath);
const context = createBrowserLikeContext();
vm.runInContext(code, context, bundlePath);
var ids = [];
var script = 'var apps = {};\n';
for (var i in apps) {
var moduleName = apps[i].moduleName;
var id = apps[i].appId || 'defaultApp';
const ids = [];
let script = 'var apps = {};\n';
for (const i in apps) {
const moduleName = apps[i].moduleName;
const id = apps[i].appId || 'defaultApp';
ids.push(id);
script += 'apps.' + id + ' = require("' + moduleName + '");\n';
}
script += 'apps;\n';
var appsInContext = vm.runInContext(script, context);
const appsInContext = vm.runInContext(script, context);
async.each(ids, function(id, done) {
appsInContext[id].once('booted', function() {
done();

View File

@ -1,36 +1,39 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var boot = require('../');
var exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox;
var fs = require('fs');
var path = require('path');
var expect = require('chai').expect;
var browserify = require('browserify');
var sandbox = require('./helpers/sandbox');
var vm = require('vm');
var createBrowserLikeContext = require('./helpers/browser').createContext;
var printContextLogs = require('./helpers/browser').printContextLogs;
const boot = require('../');
const exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox;
const packageFilter = require('./helpers/browserify').packageFilter;
const fs = require('fs');
const path = require('path');
const expect = require('chai').expect;
const browserify = require('browserify');
const sandbox = require('./helpers/sandbox');
const vm = require('vm');
const createBrowserLikeContext = require('./helpers/browser').createContext;
const printContextLogs = require('./helpers/browser').printContextLogs;
var compileStrategies = {
'default': function(appDir) {
var b = browserify({
const compileStrategies = {
default: function(appDir) {
const b = browserify({
basedir: appDir,
debug: true,
packageFilter,
});
b.require('./app.js', {expose: 'browser-app'});
return b;
},
'coffee': function(appDir) {
var b = browserify({
coffee: function(appDir) {
const b = browserify({
basedir: appDir,
extensions: ['.coffee'],
debug: true,
packageFilter,
});
b.transform('coffeeify');
@ -45,18 +48,20 @@ describe('browser support', function() {
beforeEach(sandbox.reset);
it('has API for bundling and executing boot instructions', function(done) {
var appDir = path.resolve(__dirname, './fixtures/browser-app');
const appDir = path.resolve(__dirname, './fixtures/browser-app');
browserifyTestApp(appDir, function(err, bundlePath) {
if (err) return done(err);
var app = executeBundledApp(bundlePath, function(err) {
const app = executeBundledApp(bundlePath, function(err) {
if (err) return done(err);
// configured in fixtures/browser-app/boot/configure.js
expect(app.settings).to.have.property('custom-key', 'custom-value');
expect(Object.keys(app.models)).to.include('Customer');
expect(app.models.Customer.settings)
.to.have.property('_customized', 'Customer');
expect(app.models.Customer.settings).to.have.property(
'_customized',
'Customer',
);
// configured in fixtures/browser-app/component-config.json
// and fixtures/browser-app/components/dummy-component.js
@ -67,17 +72,17 @@ describe('browser support', function() {
});
it('loads mixins', function(done) {
var appDir = path.resolve(__dirname, './fixtures/browser-app');
var options = {
const appDir = path.resolve(__dirname, './fixtures/browser-app');
const options = {
appRootDir: appDir,
};
browserifyTestApp(options, function(err, bundlePath) {
if (err) return done(err);
var app = executeBundledApp(bundlePath, function(err) {
var modelBuilder = app.registry.modelBuilder;
var registry = modelBuilder.mixins.mixins;
const app = executeBundledApp(bundlePath, function(err) {
const modelBuilder = app.registry.modelBuilder;
const registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['TimeStamps']);
expect(app.models.Customer.timeStampsMixin).to.eql(true);
@ -88,19 +93,21 @@ describe('browser support', function() {
it('supports coffee-script files', function(done) {
// add coffee-script to require.extensions
require('coffee-script/register');
require('coffeescript/register');
var appDir = path.resolve(__dirname, './fixtures/coffee-app');
const appDir = path.resolve(__dirname, './fixtures/coffee-app');
browserifyTestApp(appDir, 'coffee', function(err, bundlePath) {
if (err) return done(err);
var app = executeBundledApp(bundlePath, function(err) {
const app = executeBundledApp(bundlePath, function(err) {
// configured in fixtures/browser-app/boot/configure.coffee
expect(app.settings).to.have.property('custom-key', 'custom-value');
expect(Object.keys(app.models)).to.include('Customer');
expect(app.models.Customer.settings)
.to.have.property('_customized', 'Customer');
expect(app.models.Customer.settings).to.have.property(
'_customized',
'Customer',
);
done();
});
});
@ -109,15 +116,14 @@ describe('browser support', function() {
function browserifyTestApp(options, strategy, next) {
// set default args
if (((typeof strategy) === 'function') && !next) {
if (typeof strategy === 'function' && !next) {
next = strategy;
strategy = undefined;
}
if (!strategy)
strategy = 'default';
if (!strategy) strategy = 'default';
var appDir = typeof(options) === 'object' ? options.appRootDir : options;
var b = compileStrategies[strategy](appDir);
const appDir = typeof options === 'object' ? options.appRootDir : options;
const b = compileStrategies[strategy](appDir);
boot.compileToBrowserify(options, b, function(err) {
exportBrowserifyToFile(b, 'browser-app-bundle.js', next);
@ -125,10 +131,10 @@ function browserifyTestApp(options, strategy, next) {
}
function executeBundledApp(bundlePath, done) {
var code = fs.readFileSync(bundlePath);
var context = createBrowserLikeContext();
const code = fs.readFileSync(bundlePath);
const context = createBrowserLikeContext();
vm.runInContext(code, context, bundlePath);
var app = vm.runInContext('require("browser-app")', context);
const app = vm.runInContext('require("browser-app")', context);
app.once('booted', function(err) {
printContextLogs(context);
done(err, app);

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,31 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var async = require('async');
var boot = require('../');
var path = require('path');
var loopback = require('loopback');
var assert = require('assert');
const async = require('async');
const boot = require('../');
const path = require('path');
const loopback = require('loopback');
const assert = require('assert');
var chai = require('chai');
var dirtyChai = require('dirty-chai');
var expect = chai.expect;
const chai = require('chai');
const dirtyChai = require('dirty-chai');
const expect = chai.expect;
chai.use(dirtyChai);
var fs = require('fs-extra');
var sandbox = require('./helpers/sandbox');
var appdir = require('./helpers/appdir');
var supertest = require('supertest');
var os = require('os');
const fs = require('fs-extra');
const sandbox = require('./helpers/sandbox');
const appdir = require('./helpers/appdir');
const supertest = require('supertest');
const os = require('os');
var SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-app');
var ENV_APP = path.join(__dirname, 'fixtures', 'env-app');
const SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-app');
const ENV_APP = path.join(__dirname, 'fixtures', 'env-app');
var app;
let app;
describe('executor', function() {
beforeEach(sandbox.reset);
@ -43,7 +43,7 @@ describe('executor', function() {
delete process.bootFlags;
});
var dummyInstructions = someInstructions({
const dummyInstructions = someInstructions({
application: {
port: 0,
host: '127.0.0.1',
@ -134,7 +134,7 @@ describe('executor', function() {
expect(app.models.Customer).to.exist();
expect(app.models.Customer.settings._customized).to.be.equal('Customer');
var UserModel = app.registry.getModel('User');
const UserModel = app.registry.getModel('User');
expect(UserModel.settings._customized).to.equal('Base');
done();
});
@ -232,7 +232,7 @@ describe('executor', function() {
});
it('throws on bad require() call inside boot script', function(done) {
var file = appdir.writeFileSync('boot/badScript.js',
const file = appdir.writeFileSync('boot/badScript.js',
'require("doesnt-exist"); module.exports = {};');
boot.execute(app, someInstructions({bootScripts: [file]}),
@ -261,7 +261,7 @@ describe('executor', function() {
// loopback-datasource-juggler quirk:
// Model.dataSources has modelBuilder as the default value,
// therefore it's not enough to assert a false-y value
var actual = loopback.Email.dataSource instanceof loopback.DataSource ?
const actual = loopback.Email.dataSource instanceof loopback.DataSource ?
'attached' : 'not attached';
expect(actual).to.equal('not attached');
done();
@ -269,10 +269,10 @@ describe('executor', function() {
});
it('skips definition of already defined LoopBack models', function(done) {
var builtinModel = {
const builtinModel = {
name: 'User',
definition: fs.readJsonSync(
require.resolve('loopback/common/models/user.json')
require.resolve('loopback/common/models/user.json'),
),
config: {dataSource: 'db'},
sourceFile: require.resolve('loopback/common/models/user.js'),
@ -306,9 +306,16 @@ describe('executor', function() {
'barLoaded',
'barSyncLoaded',
'fooLoaded',
'promiseLoaded',
'thenableLoaded',
'barStarted',
'barFinished',
'barSyncExecuted',
'promiseStarted',
'promiseFinished',
'thenableStarted',
'thenableFinished',
'umdLoaded',
]);
});
});
@ -322,60 +329,132 @@ describe('executor', function() {
'barLoaded',
'barSyncLoaded',
'fooLoaded',
'promiseLoaded',
'thenableLoaded',
'barStarted',
'barFinished',
'barSyncExecuted',
'promiseStarted',
'promiseFinished',
'thenableStarted',
'thenableFinished',
'umdLoaded',
]);
done();
});
});
});
});
describe('for mixins', function() {
var options;
beforeEach(function() {
appdir.writeFileSync('custom-mixins/example.js',
'module.exports = ' +
'function(Model, options) {}');
describe('with boot script returning a rejected promise', function() {
before(function() {
// Tell simple-app/boot/reject.js to return a rejected promise
process.rejectPromise = true;
});
appdir.writeFileSync('custom-mixins/time-stamps.js',
'module.exports = ' +
'function(Model, options) {}');
after(function() {
delete process.rejectPromise;
});
appdir.writeConfigFileSync('custom-mixins/time-stamps.json', {
name: 'Timestamping',
it('receives rejected promise as callback error',
function(done) {
simpleAppInstructions(function(err, context) {
if (err) return done(err);
boot.execute(app, context.instructions, function(err) {
expect(err).to.exist.and.be.an.instanceOf(Error)
.with.property('message', 'reject');
done();
});
});
});
});
options = {
appRootDir: appdir.PATH,
};
describe('with boot script throwing an error', function() {
before(function() {
// Tell simple-app/boot/throw.js to throw an error
process.throwError = true;
});
after(function() {
delete process.throwError;
});
it('receives thrown error as callback errors',
function(done) {
simpleAppInstructions(function(err, context) {
if (err) return done(err);
boot.execute(app, context.instructions, function(err) {
expect(err).to.exist.and.be.an.instanceOf(Error)
.with.property('message', 'throw');
done();
});
});
});
});
describe('with boot script returning a promise and calling callback',
function() {
before(function() {
process.promiseAndCallback = true;
});
it('defines mixins from instructions - using `mixinDirs`',
function(done) {
options.mixinDirs = ['./custom-mixins'];
boot(app, options, function(err) {
if (err) return done(err);
var modelBuilder = app.registry.modelBuilder;
var registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['Example', 'Timestamping']);
done();
});
});
after(function() {
delete process.promiseAndCallback;
});
it('defines mixins from instructions - using `mixinSources`',
function(done) {
options.mixinSources = ['./custom-mixins'];
boot(app, options, function(err) {
if (err) return done(err);
var modelBuilder = app.registry.modelBuilder;
var registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['Example', 'Timestamping']);
done();
});
it('should only call the callback once', function(done) {
simpleAppInstructions(function(err, context) {
if (err) return done(err);
// Note: Mocha will fail this test if done() is called twice
boot.execute(app, context.instructions, done);
});
});
});
describe('for mixins', function() {
let options;
beforeEach(function() {
appdir.writeFileSync('custom-mixins/example.js',
'module.exports = ' +
'function(Model, options) {}');
appdir.writeFileSync('custom-mixins/time-stamps.js',
'module.exports = ' +
'function(Model, options) {}');
appdir.writeConfigFileSync('custom-mixins/time-stamps.json', {
name: 'Timestamping',
});
options = {
appRootDir: appdir.PATH,
};
});
it('defines mixins from instructions - using `mixinDirs`',
function(done) {
options.mixinDirs = ['./custom-mixins'];
boot(app, options, function(err) {
if (err) return done(err);
const modelBuilder = app.registry.modelBuilder;
const registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['Example', 'Timestamping']);
done();
});
});
it('defines mixins from instructions - using `mixinSources`',
function(done) {
options.mixinSources = ['./custom-mixins'];
boot(app, options, function(err) {
if (err) return done(err);
const modelBuilder = app.registry.modelBuilder;
const registry = modelBuilder.mixins.mixins;
expect(Object.keys(registry)).to.eql(['Example', 'Timestamping']);
done();
});
});
});
describe('with PaaS and npm env variables', function() {
@ -502,7 +581,7 @@ describe('executor', function() {
});
it('should respect named pipes port values in ENV', function(done) {
var NAMED_PORT = '\\.\\pipe\\test';
const NAMED_PORT = '\\.\\pipe\\test';
process.env.PORT = NAMED_PORT;
boot.execute(app, someInstructions({application: {port: 3000}}),
function(err) {
@ -520,8 +599,7 @@ describe('executor', function() {
it('should parse a simple config variable', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{path: '${restApiRoot}'}
), function(err) {
{path: '${restApiRoot}'}), function(err) {
if (err) return done(err);
supertest(app).get('/').end(function(err, res) {
@ -535,8 +613,7 @@ describe('executor', function() {
it('should parse simple config variable from env var', function(done) {
process.env.restApiRoot = '/url-from-env-var';
boot.execute(app, simpleMiddlewareConfig('routes',
{path: '${restApiRoot}'}
), function(err) {
{path: '${restApiRoot}'}), function(err) {
if (err) return done(err);
supertest(app).get('/url-from-env-var').end(function(err, res) {
@ -550,8 +627,7 @@ describe('executor', function() {
it('dynamic variable from `env var` should have' +
' precedence over app.get()', function(done) {
process.env.restApiRoot = '/url-from-env-var';
var bootInstructions;
bootInstructions = simpleMiddlewareConfig('routes',
const bootInstructions = simpleMiddlewareConfig('routes',
{path: '${restApiRoot}'});
bootInstructions.application = {restApiRoot: '/url-from-config'};
boot.execute(app, someInstructions(bootInstructions), function(err) {
@ -568,8 +644,7 @@ describe('executor', function() {
it('should parse multiple config variables', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{path: '${restApiRoot}', env: '${env}'}
), function(err) {
{path: '${restApiRoot}', env: '${env}'}), function(err) {
if (err) return done(err);
supertest(app).get('/').end(function(err, res) {
@ -583,14 +658,13 @@ describe('executor', function() {
it('should parse config variables in an array', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{paths: ['${restApiRoot}']}
), function(err) {
{paths: ['${restApiRoot}']}), function(err) {
if (err) return done(err);
supertest(app).get('/').end(function(err, res) {
if (err) return done(err);
expect(res.body.paths).to.eql(
[app.get('restApiRoot')]
[app.get('restApiRoot')],
);
done();
});
@ -599,8 +673,7 @@ describe('executor', function() {
it('should parse config variables in an object', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{info: {path: '${restApiRoot}'}}
), function(err) {
{info: {path: '${restApiRoot}'}}), function(err) {
if (err) return done(err);
supertest(app).get('/').end(function(err, res) {
@ -615,8 +688,7 @@ describe('executor', function() {
it('should parse config variables in a nested object', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{nested: {info: {path: '${restApiRoot}'}}}
), function(err) {
{nested: {info: {path: '${restApiRoot}'}}}), function(err) {
if (err) return done(err);
supertest(app).get('/').end(function(err, res) {
@ -631,8 +703,7 @@ describe('executor', function() {
it('should parse config variables with null values', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{nested: {info: {path: '${restApiRoot}', some: null}}}
), function(err) {
{nested: {info: {path: '${restApiRoot}', some: null}}}), function(err) {
if (err) return done(err);
supertest(app).get('/').end(function(err, res) {
@ -649,10 +720,10 @@ describe('executor', function() {
});
it('should not parse invalid config variables', function(done) {
var invalidDataTypes = [undefined, function() {
const invalidDataTypes = [undefined, function() {
}];
async.each(invalidDataTypes, function(invalidDataType, cb) {
var config = simpleMiddlewareConfig('routes', {
const config = simpleMiddlewareConfig('routes', {
path: invalidDataType,
});
boot.execute(app, config, function(err) {
@ -670,7 +741,7 @@ describe('executor', function() {
});
it('should parse valid config variables', function(done) {
var config = simpleMiddlewareConfig('routes', {
const config = simpleMiddlewareConfig('routes', {
props: ['a', '${vVar}', 1, true, function() {
}, {x: 1, y: '${y}'}],
});
@ -687,11 +758,12 @@ describe('executor', function() {
});
it('should preserve object prototypes', function(done) {
var config = simpleMiddlewareConfig(
const config = simpleMiddlewareConfig(
'routes',
// IMPORTANT we need more than one item to trigger the original issue
[/^\/foobar/, /^\/another/],
{});
{},
);
boot.execute(app, config, function(err) {
if (err) return done(err);
@ -710,7 +782,7 @@ describe('executor', function() {
it('should parse a simple config variable', function(done) {
boot.execute(app, simpleComponentConfig(
{path: '${restApiRoot}'}
{path: '${restApiRoot}'},
), function(err) {
if (err) return done(err);
@ -723,12 +795,12 @@ describe('executor', function() {
});
it('should parse config from `env-var` and `config`', function(done) {
var bootInstructions = simpleComponentConfig(
const bootInstructions = simpleComponentConfig(
{
path: '${restApiRoot}',
fromConfig: '${DYNAMIC_CONFIG}',
fromEnvVar: '${DYNAMIC_ENVVAR}',
}
},
);
// result should get value from config.json
@ -748,8 +820,8 @@ describe('executor', function() {
});
it('`env-var` should have precedence over `config`', function(done) {
var key = 'DYNAMIC_VARIABLE';
var bootInstructions = simpleComponentConfig({
const key = 'DYNAMIC_VARIABLE';
const bootInstructions = simpleComponentConfig({
path: '${restApiRoot}',
isDynamic: '${' + key + '}',
});
@ -768,7 +840,7 @@ describe('executor', function() {
it('should parse multiple config variables', function(done) {
boot.execute(app, simpleComponentConfig(
{path: '${restApiRoot}', env: '${env}'}
{path: '${restApiRoot}', env: '${env}'},
), function(err) {
if (err) return done(err);
@ -783,14 +855,14 @@ describe('executor', function() {
it('should parse config variables in an array', function(done) {
boot.execute(app, simpleComponentConfig(
{paths: ['${restApiRoot}']}
{paths: ['${restApiRoot}']},
), function(err) {
if (err) return done(err);
supertest(app).get('/component').end(function(err, res) {
if (err) return done(err);
expect(res.body.paths).to.eql(
[app.get('restApiRoot')]
[app.get('restApiRoot')],
);
done();
});
@ -799,7 +871,7 @@ describe('executor', function() {
it('should parse config variables in an object', function(done) {
boot.execute(app, simpleComponentConfig(
{info: {path: '${restApiRoot}'}}
{info: {path: '${restApiRoot}'}},
), function(err) {
if (err) return done(err);
@ -815,7 +887,7 @@ describe('executor', function() {
it('should parse config variables in a nested object', function(done) {
boot.execute(app, simpleComponentConfig(
{nested: {info: {path: '${restApiRoot}'}}}
{nested: {info: {path: '${restApiRoot}'}}},
), function(err) {
if (err) return done(err);
@ -831,7 +903,7 @@ describe('executor', function() {
});
it('calls function exported by boot/init.js', function(done) {
var file = appdir.writeFileSync('boot/init.js',
const file = appdir.writeFileSync('boot/init.js',
'module.exports = function(app) { app.fnCalled = true; };');
delete app.fnCalled;
@ -844,7 +916,7 @@ describe('executor', function() {
});
it('configures middleware', function(done) {
var pushNamePath = require.resolve('./helpers/push-name-middleware');
const pushNamePath = require.resolve('./helpers/push-name-middleware');
boot.execute(app, someInstructions({
middleware: {
@ -888,7 +960,7 @@ describe('executor', function() {
.get('/')
.end(function(err, res) {
if (err) return done(err);
var names = (res.headers.names || '').split(',');
const names = (res.headers.names || '').split(',');
expect(names).to.eql(['initial', 'custom', 'routes']);
done();
});
@ -916,7 +988,7 @@ describe('executor', function() {
.get('/')
.end(function(err, res) {
if (err) return done(err);
var EXPECTED_TEXT = '<!DOCTYPE html>\n<html>\n<head lang="en">\n' +
const EXPECTED_TEXT = '<!DOCTYPE html>\n<html>\n<head lang="en">\n' +
' <meta charset="UTF-8">\n <title>simple-app</title>\n' +
'</head>\n<body>\n<h1>simple-app</h1>\n' +
'</body>\n</html>';
@ -958,7 +1030,8 @@ describe('executor', function() {
if (err) return done(err);
expect(Object.keys(require.cache)).to.include(
appdir.resolve('components/test-component/index.js'));
appdir.resolve('components/test-component/index.js'),
);
expect(app.componentOptions).to.eql({option: 'value'});
done();
@ -978,35 +1051,37 @@ describe('executor', function() {
if (err) return done(err);
expect(Object.keys(require.cache)).to.not.include(
appdir.resolve('components/test-component/index.js'));
appdir.resolve('components/test-component/index.js'),
);
done();
});
});
it('disables component if overrided by production configuration',
function(done) {
appdir.writeConfigFileSync('component-config.json', {
'./components/test-component': {},
});
appdir.writeConfigFileSync('component-config.production.json', {
'./components/test-component': null,
});
function(done) {
appdir.writeConfigFileSync('component-config.json', {
'./components/test-component': {},
});
appdir.writeConfigFileSync('component-config.production.json', {
'./components/test-component': null,
});
appdir.writeFileSync('components/test-component/index.js',
'module.exports = ' +
appdir.writeFileSync('components/test-component/index.js',
'module.exports = ' +
'function(app, options) { app.componentOptions = options; }');
boot(app, {appRootDir: appdir.PATH, env: 'production'}, function(err) {
if (err) return done(err);
boot(app, {appRootDir: appdir.PATH, env: 'production'}, function(err) {
if (err) return done(err);
expect(Object.keys(require.cache)).to.not.include(
appdir.resolve('components/test-component/index.js'));
done();
expect(Object.keys(require.cache)).to.not.include(
appdir.resolve('components/test-component/index.js'),
);
done();
});
});
});
it('configures middleware (that requires `this`)', function(done) {
var passportPath = require.resolve('./fixtures/passport');
const passportPath = require.resolve('./fixtures/passport');
boot.execute(app, someInstructions({
middleware: {
@ -1046,7 +1121,7 @@ describe('executor', function() {
});
describe('when booting with lazy connect', function() {
var SAMPLE_INSTRUCTION = someInstructions({
const SAMPLE_INSTRUCTION = someInstructions({
dataSources: {
lazyConnector: {
connector: 'testLazyConnect',
@ -1054,7 +1129,7 @@ describe('executor', function() {
},
},
});
var connectTriggered = true;
let connectTriggered = true;
beforeEach(function() {
app.connector('testLazyConnect', {
@ -1108,13 +1183,14 @@ describe('executor', function() {
});
it('should convert dynamic variable for datasource', function(done) {
var datasource = {
const datasource = {
mydb: {
connector: 'memory',
host: '${DYNAMIC_HOST}',
port: '${DYNAMIC_PORT}',
},
};
var bootInstructions = {dataSources: datasource};
const bootInstructions = {dataSources: datasource};
process.env.DYNAMIC_PORT = '10007';
process.env.DYNAMIC_HOST = '123.321.123.132';
@ -1127,27 +1203,34 @@ describe('executor', function() {
});
it('should resolve dynamic config via app.get()', function(done) {
var datasource = {
mydb: {host: '${DYNAMIC_HOST}'},
const datasource = {
mydb: {
connector: 'memory',
host: '${DYNAMIC_HOST}',
},
};
var bootInstructions = {
const bootInstructions = {
application: {DYNAMIC_HOST: '127.0.0.4'},
dataSources: datasource,
};
boot.execute(app, someInstructions(bootInstructions), function() {
expect(app.get('DYNAMIC_HOST')).to.equal('127.0.0.4');
expect(app.datasources.mydb.settings.host).to.equal(
'127.0.0.4');
'127.0.0.4',
);
done();
});
});
it('should take ENV precedence over config.json', function(done) {
process.env.DYNAMIC_HOST = '127.0.0.2';
var datasource = {
mydb: {host: '${DYNAMIC_HOST}'},
const datasource = {
mydb: {
connector: 'memory',
host: '${DYNAMIC_HOST}',
},
};
var bootInstructions = {
const bootInstructions = {
application: {DYNAMIC_HOST: '127.0.0.3'},
dataSources: datasource,
};
@ -1159,10 +1242,13 @@ describe('executor', function() {
});
it('empty dynamic conf should resolve as `undefined`', function(done) {
var datasource = {
mydb: {host: '${DYNAMIC_HOST}'},
const datasource = {
mydb: {
connector: 'memory',
host: '${DYNAMIC_HOST}',
},
};
var bootInstructions = {dataSources: datasource};
const bootInstructions = {dataSources: datasource};
boot.execute(app, someInstructions(bootInstructions), function() {
expect(app.get('DYNAMIC_HOST')).to.be.undefined();
@ -1179,7 +1265,7 @@ function simpleMiddlewareConfig(phase, paths, params) {
paths = undefined;
}
var config = {
const config = {
phase: phase,
params: params,
};
@ -1228,7 +1314,7 @@ assert.isFunc = function(obj, name) {
};
function someInstructions(values) {
var result = {
const result = {
application: values.application || {},
models: values.models || [],
dataSources: values.dataSources || {db: {connector: 'memory'}},
@ -1241,7 +1327,7 @@ function someInstructions(values) {
result.env = values.env;
if (values.files) {
for (var k in values.files)
for (const k in values.files)
result.files[k] = values.files[k];
}

View File

@ -1,14 +1,14 @@
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('loopback');
var boot = require('../../../');
const loopback = require('loopback');
const boot = require('../../../');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, {
appId: 'browserApp2',
appRootDir: __dirname,

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2015. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,12 +1,12 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var loopback = require('loopback');
var boot = require('../../../');
const loopback = require('loopback');
const boot = require('../../../');
var app = module.exports = loopback();
const app = module.exports = loopback();
boot(app, __dirname);

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2015. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

2
test/fixtures/empty-app/config.json vendored Normal file
View File

@ -0,0 +1,2 @@
{
}

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2015. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,11 +1,11 @@
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var framework = {
const framework = {
initialize: function(passport) {
return function(req, res, next) {
req._passport = passport;
@ -15,7 +15,7 @@ var framework = {
},
};
var Passport = function() {
const Passport = function() {
this._framework = framework;
};

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2015. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -0,0 +1,15 @@
// Copyright IBM Corp. 2017,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
const Promise = require('bluebird');
module.exports = function(app, callback) {
callback();
if (process.promiseAndCallback) {
return Promise.reject();
}
};

View File

@ -0,0 +1,21 @@
// Copyright IBM Corp. 2017,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
const Promise = require('bluebird');
process.bootFlags.push('promiseLoaded');
module.exports = function(app) {
process.bootFlags.push('promiseStarted');
return Promise.resolve({
then: function(onFulfill, onReject) {
process.nextTick(function() {
process.bootFlags.push('promiseFinished');
onFulfill();
});
},
});
};

14
test/fixtures/simple-app/boot/reject.js vendored Normal file
View File

@ -0,0 +1,14 @@
// Copyright IBM Corp. 2017,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
const Promise = require('bluebird');
module.exports = function(app) {
if (process.rejectPromise) {
return Promise.reject(new Error('reject'));
}
};

View File

@ -0,0 +1,19 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
process.bootFlags.push('thenableLoaded');
module.exports = function(app) {
process.bootFlags.push('thenableStarted');
return {
then: function(onFulfill, onReject) {
process.nextTick(function() {
process.bootFlags.push('thenableFinished');
onFulfill();
});
},
};
};

12
test/fixtures/simple-app/boot/throw.js vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(app) {
if (process.throwError) {
throw new Error('throw');
}
};

View File

@ -0,0 +1,13 @@
// Copyright IBM Corp. 2018,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = {
default: function() {
process.bootFlags.push('umdLoaded');
},
};
Object.defineProperty(module.exports, '__esModule', {value: true});

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,3 +1,8 @@
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = function(opitions) {

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2015. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,18 +1,18 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path');
var fs = require('fs-extra');
var extend = require('util')._extend;
var sandbox = require('./sandbox');
const path = require('path');
const fs = require('fs-extra');
const extend = require('util')._extend;
const sandbox = require('./sandbox');
var appdir = exports;
const appdir = exports;
var PATH = appdir.PATH = null;
let PATH = appdir.PATH = null;
appdir.init = function(cb) {
// Node's module loader has a very aggressive caching, therefore
@ -20,7 +20,7 @@ appdir.init = function(cb) {
// The code here is used to generate a random string
require('crypto').randomBytes(5, function(err, buf) {
if (err) return cb(err);
var randomStr = buf.toString('hex');
const randomStr = buf.toString('hex');
PATH = appdir.PATH = sandbox.resolve(randomStr);
cb(null, appdir.PATH);
});
@ -49,7 +49,7 @@ appdir.writeConfigFileSync = function(name, json) {
};
appdir.writeFileSync = function(name, content) {
var filePath = this.resolve(name);
const filePath = this.resolve(name);
fs.mkdirsSync(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
return filePath;

View File

@ -1,16 +1,17 @@
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var vm = require('vm');
const vm = require('vm');
function createContext() {
var context = {
const context = {
// required by browserify
XMLHttpRequest: function() { throw new Error('not implemented'); },
XMLHttpRequest: function() {},
clearTimeout: function() {},
FormData: function() { throw new Error('not implemented'); },
localStorage: {
@ -32,7 +33,7 @@ function createContext() {
DataView: DataView,
crypto: {
getRandomValues: function(typedArray) {
var randomBuffer = require('crypto').randomBytes(typedArray.length);
const randomBuffer = require('crypto').randomBytes(typedArray.length);
// This implementation is not secure: we take random 8bit values
// and assign them to 8/16/32bit values, leaving high-order bits
// filled with zeroes.
@ -72,9 +73,9 @@ function createContext() {
exports.createContext = createContext;
function printContextLogs(context) {
var k, ix; // see https://github.com/eslint/eslint/issues/5744
let k, ix; // see https://github.com/eslint/eslint/issues/5744
for (k in context.console._logs) {
var items = context.console._logs[k];
const items = context.console._logs[k];
for (ix in items) {
console[k].apply(console, items[ix]);
}

View File

@ -1,16 +1,16 @@
// Copyright IBM Corp. 2015. All Rights Reserved.
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var fs = require('fs');
var sandbox = require('./sandbox');
const fs = require('fs');
const sandbox = require('./sandbox');
function exportToSandbox(b, fileName, callback) {
var bundlePath = sandbox.resolve(fileName);
var out = fs.createWriteStream(bundlePath);
const bundlePath = sandbox.resolve(fileName);
const out = fs.createWriteStream(bundlePath);
b.bundle().pipe(out);
out.on('error', function(err) {
@ -21,3 +21,16 @@ function exportToSandbox(b, fileName, callback) {
});
}
exports.exportToSandbox = exportToSandbox;
exports.packageFilter = function packageFilter(pkg, dir) {
// async@3 (used e.g. by loopback-connector) is specifying custom
// browserify config, in particular it wants to apply transformation
// `babelify`. We don't have `babelify` installed because we are
// testing using latest Chrome and thus don't need any transpilation.
// Let's remove the browserify config from the package and force
// browserify to use our config instead.
if (pkg.name === 'async') {
delete pkg.browserify;
}
return pkg;
};

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,14 +1,14 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var fs = require('fs-extra');
var path = require('path');
const fs = require('fs-extra');
const path = require('path');
var sandbox = exports;
const sandbox = exports;
sandbox.PATH = path.join(__dirname, '..', 'sandbox');
sandbox.reset = function() {
@ -17,7 +17,7 @@ sandbox.reset = function() {
};
sandbox.resolve = function() {
var args = Array.prototype.slice.apply(arguments);
const args = Array.prototype.slice.apply(arguments);
args.unshift(sandbox.PATH);
return path.resolve.apply(path.resolve, args);
};

View File

@ -1,14 +1,14 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2016,2019. All Rights Reserved.
// Node module: loopback-boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var utils = require('../lib/utils');
var expect = require('chai').expect;
var sandbox = require('./helpers/sandbox');
var appdir = require('./helpers/appdir');
const utils = require('../lib/utils');
const expect = require('chai').expect;
const sandbox = require('./helpers/sandbox');
const appdir = require('./helpers/appdir');
describe('utils', function() {
beforeEach(sandbox.reset);
@ -17,13 +17,13 @@ describe('utils', function() {
});
describe('fileExistsSync', function() {
it('returns false when a file does not exist', function() {
var doesNotExist = sandbox.resolve('does-not-exist.json');
const doesNotExist = sandbox.resolve('does-not-exist.json');
expect(utils.fileExistsSync(doesNotExist))
.to.equal(false);
});
it('returns true when a file does exist', function() {
var doesExist = appdir.writeConfigFileSync('does-exist.json', {
const doesExist = appdir.writeConfigFileSync('does-exist.json', {
exists: true,
});
expect(utils.fileExistsSync(doesExist))