diff --git a/.eslintrc.js b/.eslintrc.js
index 382f20680fd..9fa379f73aa 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -56,7 +56,7 @@ module.exports = {
'.mocharc.js',
'.eslintrc.js',
'.prettierrc.js',
- 'bin/*',
+ 'bin/**',
'packages/private-build-infra/src/**/*.js',
'packages/unpublished-relationship-performance-test-app/bin/*.js',
'packages/unpublished-test-infra/src/**/*.js',
@@ -109,12 +109,13 @@ module.exports = {
// bin files
{
- files: ['bin/*', 'packages/unpublished-relationship-performance-test-app/bin/*'],
+ files: ['bin/**', 'packages/unpublished-relationship-performance-test-app/bin/*'],
// eslint-disable-next-line node/no-unpublished-require
rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
'no-console': 'off',
'no-process-exit': 'off',
'node/no-unpublished-require': 'off',
+ 'node/no-unsupported-features/node-builtins': 'off',
}),
},
],
diff --git a/.github/workflows/asset-size-check.yml b/.github/workflows/asset-size-check.yml
new file mode 100644
index 00000000000..a87395a8e7e
--- /dev/null
+++ b/.github/workflows/asset-size-check.yml
@@ -0,0 +1,90 @@
+name: AssetSizeCheck
+
+on:
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ asset-size-check:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - uses: actions/setup-node@v1
+ with:
+ node-version: 12.x
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ - name: Check SHA
+ run: |
+ sha=$(git rev-parse --short=8 HEAD)
+ echo "HEAD sha=$sha"
+ echo "GITHUB_SHA sha=$GITHUB_SHA"
+ mkdir -p tmp
+ echo $sha > tmp/sha-for-check.txt
+ originSha=$(git rev-parse HEAD^2)
+ echo $originSha > tmp/sha-for-commit.txt
+ git show --format=short --no-patch $originSha
+ - name: Checkout master
+ run: git checkout master
+ - name: Install dependencies for master
+ run: yarn install
+ - name: Build Production master
+ # This will leave the assets in a dist that is maintained when
+ # We switch back to the primary branch
+ run: yarn workspace ember-data ember build -e production
+ - name: Checkout ${{github.ref}}
+ # We checkout the PR Branch before parsing the master vendor file
+ # So that we are always using the current analysis tooling
+ run: |
+ sha=$(cat tmp/sha-for-check.txt)
+ git checkout --progress --force $sha
+ - name: Install dependencies for ${{github.ref}}
+ run: yarn install
+ - name: Parse Master Assets
+ run: |
+ node ./bin/asset-size-tracking/generate-analysis.js
+ mkdir -p tmp
+ mkdir -p tmp/asset-sizes
+ node ./bin/asset-size-tracking/print-analysis.js -show > tmp/asset-sizes/master-analysis.txt
+ - name: Upload Master Dist Artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: master-dist
+ path: packages/-ember-data/dist/assets
+ - name: Build Production ${{github.ref}}
+ run: yarn workspace ember-data ember build -e production
+ - name: Test Asset Sizes
+ run: |
+ mkdir -p tmp
+ mkdir -p tmp/asset-sizes
+ set -o pipefail
+ node ./bin/asset-size-tracking/generate-diff.js | tee tmp/asset-sizes/diff.txt
+ - name: Prepare Data For Report
+ if: failure() || success()
+ run: |
+ node ./bin/asset-size-tracking/generate-analysis.js
+ - name: Print Asset Size Report
+ if: failure() || success()
+ run: |
+ set -o pipefail
+ node ./bin/asset-size-tracking/print-analysis.js | tee tmp/asset-sizes/commit-analysis.txt
+ - name: Upload ${{github.ref}} Dist Artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: commit-dist
+ path: packages/-ember-data/dist/assets
+ - name: Upload Report Artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: reports
+ path: tmp/asset-sizes
+ - name: Report Asset Sizes
+ if: failure() || success()
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ COMMENT_MARKER="Asset Size Report for "=
+ sha=$(cat tmp/sha-for-commit.txt)
+ node ./bin/asset-size-tracking/src/create-comment-text.js $sha > tmp/asset-sizes/comment.txt
+ COMMENT_TEXT="@./tmp/asset-sizes/comment.txt"
+ source bin/asset-size-tracking/src/post-comment.sh
diff --git a/.gitignore b/.gitignore
index 71ac20c959c..a2bcc724cb9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ tmp
# dependencies
bower_components
node_modules
+bin/asset-size-tracking/current-data.json
# misc
.env*
diff --git a/bin/asset-size-tracking/generate-analysis.js b/bin/asset-size-tracking/generate-analysis.js
new file mode 100644
index 00000000000..f0855a33ec4
--- /dev/null
+++ b/bin/asset-size-tracking/generate-analysis.js
@@ -0,0 +1,20 @@
+'use strict';
+/**
+ * Analyze Ember-Data Modules
+ *
+ * Generates a JSON file with details of size costs of each individual module
+ * and package. You should crate a production build of the ember-data
+ * package prior to running this script.
+ *
+ */
+const fs = require('fs');
+const path = require('path');
+let INPUT_FILE = process.argv[2] || false;
+const parseModules = require('./src/parse-modules');
+const getBuiltDist = require('./src/get-built-dist');
+
+const builtAsset = getBuiltDist(INPUT_FILE);
+const library = parseModules(builtAsset);
+const outputPath = path.resolve(__dirname, './current-data.json');
+
+fs.writeFileSync(outputPath, JSON.stringify(library, null, 2));
diff --git a/bin/asset-size-tracking/generate-diff.js b/bin/asset-size-tracking/generate-diff.js
new file mode 100644
index 00000000000..c3d5a9adeec
--- /dev/null
+++ b/bin/asset-size-tracking/generate-diff.js
@@ -0,0 +1,246 @@
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const Library = require('./src/library');
+const parseModules = require('./src/parse-modules');
+const getBuiltDist = require('./src/get-built-dist');
+const chalk = require('chalk');
+const library_failure_threshold = 15;
+const package_warn_threshold = 0;
+
+let BASE_DATA_FILE = process.argv[2] || false;
+let NEW_VENDOR_FILE = process.argv[3] || false;
+
+if (!BASE_DATA_FILE) {
+ BASE_DATA_FILE = path.resolve(__dirname, './current-data.json');
+}
+
+const data = fs.readFileSync(BASE_DATA_FILE, 'utf-8');
+const current_library = Library.fromData(JSON.parse(data));
+
+const builtAsset = getBuiltDist(NEW_VENDOR_FILE);
+const new_library = parseModules(builtAsset);
+
+function getDiff(oldLibrary, newLibrary) {
+ const diff = {
+ name: oldLibrary.name,
+ currentSize: oldLibrary.absoluteSize,
+ newSize: newLibrary.absoluteSize,
+ currentSizeCompressed: oldLibrary.compressedSize,
+ newSizeCompressed: newLibrary.compressedSize,
+ packages: {},
+ };
+ oldLibrary.packages.forEach(pkg => {
+ diff.packages[pkg.name] = {
+ name: pkg.name,
+ currentSize: pkg.absoluteSize,
+ newSize: 0,
+ currentSizeCompressed: pkg.compressedSize,
+ newSizeCompressed: 0,
+ modules: {},
+ };
+ let modules = diff.packages[pkg.name].modules;
+ pkg.modules.forEach(m => {
+ modules[m.name] = {
+ name: m.name,
+ currentSize: m.absoluteSize,
+ newSize: 0,
+ currentSizeCompressed: m.compressedSize,
+ newSizeCompressed: 0,
+ };
+ });
+ });
+ newLibrary.packages.forEach(pkg => {
+ diff.packages[pkg.name] = diff.packages[pkg.name] || {
+ name: pkg.name,
+ currentSize: 0,
+ newSize: pkg.absoluteSize,
+ currentSizeCompressed: 0,
+ newSizeCompressed: pkg.compressedSize,
+ modules: {},
+ };
+ diff.packages[pkg.name].newSize = pkg.absoluteSize;
+ diff.packages[pkg.name].newSizeCompressed = pkg.compressedSize;
+ let modules = diff.packages[pkg.name].modules;
+ pkg.modules.forEach(m => {
+ modules[m.name] = modules[m.name] || {
+ name: m.name,
+ currentSize: 0,
+ newSize: m.absoluteSize,
+ currentSizeCompressed: 0,
+ newSizeCompressed: m.compressedSize,
+ };
+ modules[m.name].newSize = m.absoluteSize;
+ modules[m.name].newSizeCompressed = m.compressedSize;
+ });
+ });
+ diff.packages = Object.values(diff.packages);
+ diff.packages.forEach(pkg => {
+ pkg.modules = Object.values(pkg.modules);
+ });
+
+ return diff;
+}
+
+const diff = getDiff(current_library, new_library);
+
+function analyzeDiff(diff) {
+ let failures = [];
+ let warnings = [];
+
+ if (diff.currentSize < diff.newSize) {
+ let delta = diff.newSize - diff.currentSize;
+ let compressedDelta = diff.newSizeCompressed - diff.currentSizeCompressed;
+ if (delta > library_failure_threshold && compressedDelta > 0) {
+ failures.push(
+ `The size of the library ${diff.name} has increased by ${formatBytes(delta)} (${formatBytes(
+ compressedDelta
+ )} compressed) which exceeds the failure threshold of ${library_failure_threshold} bytes.`
+ );
+ }
+ }
+
+ diff.packages.forEach(pkg => {
+ if (pkg.currentSize < pkg.newSize) {
+ let delta = pkg.newSize - pkg.currentSize;
+ if (delta > package_warn_threshold) {
+ warnings.push(`The uncompressed size of the package ${pkg.name} has increased by ${formatBytes(delta)}.`);
+ }
+ }
+ });
+
+ return { failures, warnings };
+}
+
+function printDiff(diff) {
+ console.log('\n```\n');
+ printItem(diff);
+ diff.packages.forEach(pkg => {
+ printItem(pkg, 2);
+ pkg.modules.forEach(m => {
+ printItem(m, 4);
+ });
+ });
+ console.log('\n```\n');
+}
+
+function printItem(item, indent = 0) {
+ if (item.currentSize !== item.newSize) {
+ const indentColor = indent >= 4 ? 'grey' : indent >= 2 ? 'yellow' : indent >= 0 ? 'magenta' : 'green';
+ console.log(
+ leftPad(chalk[indentColor](item.name) + ' ' + formatSize(item, false) + ' ' + formatSize(item, true), indent * 2)
+ );
+ }
+}
+
+function formatSize(item, isCompressed = false) {
+ let size = formatBytes(isCompressed ? item.newSizeCompressed : item.newSize);
+ let delta = formatDelta(item, isCompressed);
+
+ return isCompressed ? chalk.grey(`(${chalk.white(size)} ${delta} compressed)`) : `${chalk.white(size)} ${delta}`;
+}
+
+function formatDelta(item, isCompressed = false) {
+ let delta = isCompressed ? item.newSizeCompressed - item.currentSizeCompressed : item.newSize - item.currentSize;
+
+ if (delta === 0) {
+ return chalk.black('±0 B');
+ }
+
+ if (delta < 0) {
+ return chalk.green(`${formatBytes(delta)}`);
+ } else {
+ return chalk.red(`+${formatBytes(delta)}`);
+ }
+}
+
+function humanizeNumber(n) {
+ let s = n.toFixed(2);
+ if (s.charAt(s.length - 1) === '0') {
+ s = n.toFixed(1);
+
+ if (s.charAt(s.length - 2) === '0') {
+ s = n.toFixed(0);
+ }
+ }
+ return s;
+}
+
+function formatBytes(b) {
+ let str;
+ if (b > 1024 || b < -1024) {
+ str = humanizeNumber(b / 1024) + ' KB';
+ } else {
+ str = humanizeNumber(b) + ' B';
+ }
+
+ return str;
+}
+
+function leftPad(str, len, char = ' ') {
+ for (let i = 0; i < len; i++) {
+ str = char + str;
+ }
+ return str;
+}
+
+const { failures, warnings } = analyzeDiff(diff);
+
+if (failures.length) {
+ console.log(`\n\n ${failures[0]}
`);
+ if (failures.length > 1) {
+ console.log('\nFailed Checks\n-----------------------');
+ failures.forEach(f => {
+ console.log(f);
+ });
+ }
+ if (warnings.length) {
+ console.log('\nWarnings\n-----------------------');
+ warnings.forEach(w => {
+ console.log(w);
+ });
+ }
+ console.log('\n**Changeset**\n');
+ printDiff(diff);
+ console.log('\n ');
+ process.exit(1);
+} else {
+ let delta = diff.currentSize - diff.newSize;
+ if (delta === 0) {
+ console.log(`\n\n ${diff.name} has not changed in size
`);
+ } else if (delta > 0) {
+ console.log(
+ `\n\n ${diff.name} shrank by ${formatBytes(delta)} (${formatBytes(
+ diff.currentSizeCompressed - diff.newSizeCompressed
+ )} compressed)
`
+ );
+ } else {
+ let compressedDelta = diff.newSizeCompressed - diff.currentSizeCompressed;
+ if (-1 * delta < library_failure_threshold) {
+ console.log(
+ `\n\n ${diff.name} increased by ${formatBytes(-1 * delta)} (${formatBytes(
+ compressedDelta
+ )} compressed) which is within the allowed tolerance of ${library_failure_threshold} bytes uncompressed
`
+ );
+ } else {
+ console.log(
+ `\n\n ${diff.name} increased by ${formatBytes(
+ -1 * delta
+ )} uncompressed but decreased by ${formatBytes(-1 * compressedDelta)} compressed
`
+ );
+ }
+ }
+ if (warnings.length) {
+ console.log('\nWarnings\n-----------------------');
+ warnings.forEach(w => {
+ console.log(w);
+ });
+ } else {
+ console.log('\nIf any packages had changed sizes they would be listed here.');
+ }
+ console.log('\n**Changeset**\n');
+ printDiff(diff);
+ console.log('\n ');
+ process.exit(0);
+}
diff --git a/bin/asset-size-tracking/print-analysis.js b/bin/asset-size-tracking/print-analysis.js
new file mode 100644
index 00000000000..4a533007598
--- /dev/null
+++ b/bin/asset-size-tracking/print-analysis.js
@@ -0,0 +1,17 @@
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const Library = require('./src/library');
+
+let INPUT_FILE = process.argv[2] !== '-show' ? process.argv[2] : false;
+let SHOW_MODULES = process.argv[2] === '-show' || process.argv[3] === '-show';
+
+if (!INPUT_FILE) {
+ INPUT_FILE = path.resolve(__dirname, './current-data.json');
+}
+
+const data = fs.readFileSync(INPUT_FILE, 'utf-8');
+
+const library = Library.fromData(JSON.parse(data));
+library.print(SHOW_MODULES);
diff --git a/bin/asset-size-tracking/src/create-comment-text.js b/bin/asset-size-tracking/src/create-comment-text.js
new file mode 100644
index 00000000000..9d706f3e82e
--- /dev/null
+++ b/bin/asset-size-tracking/src/create-comment-text.js
@@ -0,0 +1,15 @@
+const fs = require('fs');
+const path = require('path');
+const GITHUB_SHA = process.argv[2];
+
+const diffPath = path.resolve(__dirname, '../../../tmp/asset-sizes/diff.txt');
+const analysisPath = path.resolve(__dirname, '../../../tmp/asset-sizes/commit-analysis.txt');
+const diffText = fs.readFileSync(diffPath);
+const analysisText = fs.readFileSync(analysisPath);
+
+const commentText = `Asset Size Report for ${GITHUB_SHA}\n${diffText}\n\n Full Asset Analysis
\n\n\`\`\`${analysisText}\n\`\`\`\n `;
+const commentJSON = {
+ body: commentText,
+};
+
+console.log(JSON.stringify(commentJSON, null, 2));
diff --git a/bin/asset-size-tracking/src/get-built-dist.js b/bin/asset-size-tracking/src/get-built-dist.js
new file mode 100644
index 00000000000..2370d89b6dc
--- /dev/null
+++ b/bin/asset-size-tracking/src/get-built-dist.js
@@ -0,0 +1,37 @@
+'use strict';
+/**
+ * Analyze Ember-Data Modules
+ *
+ * Generates a JSON file with details of size costs of each individual module
+ * and package. You should crate a production build of the ember-data
+ * package prior to running this script.
+ *
+ */
+const fs = require('fs');
+const path = require('path');
+
+module.exports = function getDistFile(INPUT_FILE) {
+ if (!INPUT_FILE) {
+ try {
+ let dirPath = path.resolve(__dirname, '../../../packages/-ember-data/dist/assets');
+ let dir = fs.readdirSync(dirPath, 'utf-8');
+
+ for (let i = 0; i < dir.length; i++) {
+ let name = dir[i];
+ if (name.indexOf('vendor') !== -1 && name.indexOf('.js') !== -1) {
+ INPUT_FILE = path.resolve(dirPath, name);
+ }
+ }
+ } catch (e) {
+ console.log(`No vendor.js file found to process: ${e.message}`);
+ process.exit(1);
+ }
+
+ if (!INPUT_FILE) {
+ console.log('No vendor.js file found to process');
+ process.exit(1);
+ }
+ }
+
+ return fs.readFileSync(INPUT_FILE, 'utf-8');
+};
diff --git a/bin/asset-size-tracking/src/library.js b/bin/asset-size-tracking/src/library.js
new file mode 100644
index 00000000000..83b76e443d3
--- /dev/null
+++ b/bin/asset-size-tracking/src/library.js
@@ -0,0 +1,237 @@
+const zlib = require('zlib');
+const TablePads = {
+ name: 45,
+ bytes: 9,
+ compressedBytes: 10,
+ percentOfPackage: 13,
+};
+const BROTLI_OPTIONS = {
+ params: {
+ [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
+ },
+};
+
+function getCompressedSize(code) {
+ return Buffer.byteLength(zlib.brotliCompressSync(code, BROTLI_OPTIONS));
+}
+
+class Library {
+ constructor(name) {
+ this.name = name;
+ this.packages = [];
+ this._packageMap = {};
+ this._concatModule = '';
+ this._compressedSize = null;
+ }
+ getPackage(name) {
+ let pkg = this._packageMap[name];
+
+ if (!pkg) {
+ pkg = this._packageMap[name] = new Package(name, this);
+ this.packages.push(pkg);
+ }
+
+ return pkg;
+ }
+ get concatModule() {
+ return this._concatModule;
+ }
+ get absoluteSize() {
+ return byteCount(this.concatModule);
+ }
+ get compressedSize() {
+ return this._compressedSize || (this._compressedSize = getCompressedSize(this.concatModule));
+ }
+ sort() {
+ this.packages = this.packages.sort((a, b) => {
+ return a.compressedSize > b.compressedSize ? -1 : 1;
+ });
+ this.packages.forEach(p => p.sort());
+ }
+ print(showModules) {
+ console.log('\n\nAsset Size Report');
+ console.log('=================\n\n');
+
+ console.log(`Library: ${this.name}`);
+ console.table({
+ bytes: formatBytes(this.absoluteSize),
+ compressed: formatBytes(this.compressedSize),
+ packages: this.packages.length,
+ modules: this.packages.reduce((v, c) => v + c.modules.length, 0),
+ });
+ this.packages.forEach(p => p.print());
+ if (showModules) {
+ this.packages.forEach(p => {
+ p.modules.forEach(m => {
+ console.log('\n\n');
+ console.log(m.code);
+ });
+ });
+ }
+ }
+ toJSON() {
+ return {
+ name: this.name,
+ packages: this.packages,
+ };
+ }
+
+ static fromData(data) {
+ const library = new Library(data.name);
+ data.packages.forEach(p => {
+ const pkg = library.getPackage(p.name);
+ p.modules.forEach(m => {
+ pkg.addModule(m.name, m.code);
+ });
+ });
+ return library;
+ }
+}
+
+class Package {
+ constructor(name, library) {
+ this.name = name;
+ this.library = library;
+ this.modules = [];
+ this._concatModule = '';
+ }
+ addModule(name, code) {
+ let mod = new Module(name, this, code);
+ this.modules.push(mod);
+ this._concatModule += code;
+ this.library._concatModule += code;
+ return mod;
+ }
+ get concatModule() {
+ return this._concatModule;
+ }
+ get absoluteSize() {
+ return byteCount(this.concatModule);
+ }
+ get compressedSize() {
+ return (
+ Math.floor((this.concatModule.length / this.library.concatModule.length) * this.library.compressedSize * 100) /
+ 100
+ );
+ }
+ get percentOfLibrary() {
+ return getRelativeSizeOf(this.library, this);
+ }
+ sort() {
+ this.modules = this.modules.sort((a, b) => {
+ return a.compressedSize > b.compressedSize ? -1 : 1;
+ });
+ }
+ print() {
+ console.log('\nPackage: ' + this.name);
+ console.table({
+ bytes: formatBytes(this.absoluteSize),
+ compressed: formatBytes(this.compressedSize),
+ '% Of Library': this.percentOfLibrary,
+ });
+ console.log(
+ `\t${rightPad('Module', TablePads.name)} | ` +
+ `${rightPad('Bytes', TablePads.bytes)} | ` +
+ `${rightPad('Compressed', TablePads.compressedBytes)} | ` +
+ `${rightPad('% of Package', TablePads.percentOfPackage)} | ` +
+ `% Of Library`
+ );
+ console.log(
+ '\t-----------------------------------------------------------------------------------------------------'
+ );
+ this.modules.forEach(s => s.print());
+ }
+ toJSON() {
+ return {
+ name: this.name,
+ modules: this.modules,
+ };
+ }
+}
+
+class Module {
+ constructor(name, pkg, code) {
+ this.name = name;
+ this.package = pkg;
+ this.code = code;
+ }
+ get size() {
+ return this.code.length;
+ }
+ get absoluteSize() {
+ return byteCount(this.code);
+ }
+ get compressedSize() {
+ return (
+ Math.floor((this.size / this.package.library.concatModule.length) * this.package.library.compressedSize * 100) /
+ 100
+ );
+ }
+ get bytes() {
+ return formatBytes(this.absoluteSize);
+ }
+ get compressedBytes() {
+ return formatBytes(this.compressedSize);
+ }
+ get percentOfPackage() {
+ return getRelativeSizeOf(this.package, this);
+ }
+ get percentOfLibrary() {
+ return getRelativeSizeOf(this.package.library, this);
+ }
+ print() {
+ console.log(
+ '\t' +
+ rightPad(this.name, TablePads.name) +
+ ' | ' +
+ rightPad(this.bytes, TablePads.bytes) +
+ ' | ' +
+ rightPad(this.compressedBytes, TablePads.compressedBytes) +
+ ' | ' +
+ rightPad(this.percentOfPackage, TablePads.percentOfPackage) +
+ ' | ' +
+ this.percentOfLibrary
+ );
+ }
+ toJSON() {
+ return {
+ name: this.name,
+ code: this.code,
+ };
+ }
+}
+
+function rightPad(str, len, char = ' ') {
+ while (str.length < len) {
+ str += char;
+ }
+ return str;
+}
+
+function getRelativeSizeOf(base, component) {
+ const { absoluteSize } = component;
+ const { absoluteSize: totalSize } = base;
+
+ return `${per(absoluteSize, totalSize)}`;
+}
+
+function per(size, total) {
+ return ((size / total) * 100).toFixed(1);
+}
+
+function formatBytes(b) {
+ let str;
+ if (b > 1024) {
+ str = (b / 1024).toFixed(2) + ' KB';
+ } else {
+ str = b.toFixed(2) + ' B';
+ }
+
+ return str;
+}
+
+function byteCount(s) {
+ return encodeURI(s).split(/%..|./).length - 1;
+}
+
+module.exports = Library;
diff --git a/bin/asset-size-tracking/src/parse-modules.js b/bin/asset-size-tracking/src/parse-modules.js
new file mode 100644
index 00000000000..22273365c6d
--- /dev/null
+++ b/bin/asset-size-tracking/src/parse-modules.js
@@ -0,0 +1,42 @@
+const Library = require('./library');
+const moduleNames = ['ember-data', '@ember-data', '@ember/ordered-set', 'ember-inflector'];
+
+module.exports = function parseModules(builtAsset) {
+ let modules = builtAsset
+ .split('define(')
+ .join('MODULE_SPLIT_POINTdefine(')
+ .split('MODULE_SPLIT_POINT');
+
+ modules = modules.filter(mod => {
+ for (let i = 0; i < moduleNames.length; i++) {
+ let projectName = moduleNames[i];
+ if (mod.indexOf(projectName) === 8) {
+ return true;
+ }
+ }
+ return false;
+ });
+
+ let library = new Library('EmberData');
+
+ modules.forEach(m => {
+ let end = m.indexOf(',', 8) - 1;
+ let name = m.substring(8, end);
+
+ let packageName = 'ember-data';
+
+ if (name.indexOf('@ember-data/') === 0) {
+ let subPackageEnd = name.indexOf('/', 12);
+ packageName = name.substring(0, subPackageEnd);
+ } else if (name.indexOf('ember-inflector') === 0) {
+ packageName = 'ember-inflector';
+ } else if (name.indexOf('@ember/ordered-set') === 0) {
+ packageName = '@ember/ordered-set';
+ }
+
+ library.getPackage(packageName).addModule(name, m);
+ });
+
+ library.sort();
+ return library;
+};
diff --git a/bin/asset-size-tracking/src/post-comment.sh b/bin/asset-size-tracking/src/post-comment.sh
new file mode 100755
index 00000000000..9e7635613c5
--- /dev/null
+++ b/bin/asset-size-tracking/src/post-comment.sh
@@ -0,0 +1,73 @@
+ #!/bin/bash
+
+# Shamelessly stolen from the very awesome ShakingFingerAction
+# Written by the amazing https://twitter.com/jessfraz
+# https://github.com/jessfraz/shaking-finger-action
+# Generified to enable this form of comment management
+# for our CI Reports (AssetSize | Perf Analysis etc.)
+
+if [[ -z "$COMMENT_MARKER" ]]; then
+ echo "Set the COMMENT_MARKER env variable."
+ return 1
+fi
+
+if [[ -z "$COMMENT_TEXT" ]]; then
+ echo "Set the COMMENT_TEXT env variable."
+ return 1
+fi
+
+if [[ -z "$GITHUB_REPOSITORY" ]]; then
+ echo "Set the GITHUB_REPOSITORY env variable."
+ return 1
+fi
+
+# Github seems to be playin coy, getting access from
+# a sourced script is extremely hard
+if [[ -z "${GITHUB_TOKEN}" ]]; then
+ echo "Configure the env to include the GITHUB_TOKEN secret variable."
+ return 1
+fi
+
+URI=https://api.github.com
+API_VERSION=v3
+API_HEADER="Accept: application/vnd.github.${API_VERSION}+json; application/vnd.github.antiope-preview+json"
+AUTH_HEADER="Authorization: token ${GITHUB_TOKEN}"
+
+delete_comment_if_exists() {
+ # Get all the comments for the pull request.
+ body=$(curl -sSL -H "${AUTH_HEADER}" -H "${API_HEADER}" "${URI}/repos/${GITHUB_REPOSITORY}/issues/${NUMBER}/comments")
+
+ for row in $(echo -E "${body}" | jq --raw-output '.[] | @base64'); do
+ comment=$(echo -E "${row}" | base64 --decode | jq --raw-output '{id: .id, body: .body, author: .user.login}')
+ id=$(echo -E "$comment" | jq -r '.id')
+ b=$(echo -E "$comment" | jq -r '.body')
+
+ if [[ "$b" == *"${COMMENT_MARKER}"* ]]; then
+ # We have found our comment.
+ # Delete it.
+
+ echo "Deleting old comment ID: $id"
+ DELETE_URL="${URI}/repos/${GITHUB_REPOSITORY}/issues/comments/${id}"
+ echo $DELETE_URL;
+ curl -sSL -H "${AUTH_HEADER}" -H "${API_HEADER}" -X DELETE $DELETE_URL
+ fi
+ done
+}
+
+post_comment() {
+ curl -sSL -H "${AUTH_HEADER}" -H "${API_HEADER}" -d "$COMMENT_TEXT" -H "Content-Type: application/json" -X POST "${URI}/repos/${GITHUB_REPOSITORY}/issues/${NUMBER}/comments"
+}
+
+main() {
+ # Validate the GitHub token.
+ curl -o /dev/null -sSL -H "${AUTH_HEADER}" -H "${API_HEADER}" "${URI}/repos/${GITHUB_REPOSITORY}" || { echo "Error: Invalid repo, token or network issue!"; exit 1; }
+
+ # Get the pull request number.
+ NUMBER=$(jq --raw-output .number "$GITHUB_EVENT_PATH")
+ echo "running $GITHUB_ACTION for PR #${NUMBER}"
+
+ delete_comment_if_exists;
+ post_comment;
+}
+
+main
diff --git a/bin/relationship-performance-check b/bin/relationship-performance-check
deleted file mode 100755
index fb95b4b2077..00000000000
--- a/bin/relationship-performance-check
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-APP_PATH=packages/unpublished-relationship-performance-test-app
-HAR_REMIX_SCRIPT="$APP_PATH/bin/har-remix.js"
-WORKSPACE=relationship-performance-test-app
-CONTROl_BRANCH=master
-EXPERIMENT_BRANCH=$(git branch | sed -n -e 's/^\* \(.*\)/\1/p')
-
-git checkout $CONTROl_BRANCH
-
-if test -f $HAR_REMIX_SCRIPT; then
- yarn install
- yarn workspace $WORKSPACE ember build -e production --output-path dist-control
- git checkout $EXPERIMENT_BRANCH
- yarn install
- yarn workspace $WORKSPACE ember build -e production --output-path dist-experiment
- HR_PORT=4200 HR_GROUP=control pm2 start $HAR_REMIX_SCRIPT --name control
- HR_PORT=4201 HR_GROUP=experiment pm2 start $HAR_REMIX_SCRIPT --name experiment
- yarn workspace $WORKSPACE tracerbench:compare
- pm2 kill
-else
- echo "har-remix.js does not exist on the $CONTROl_BRANCH branch"
- git checkout $EXPERIMENT_BRANCH
-fi
\ No newline at end of file
diff --git a/bin/relationship-performance-tracking/src/generate-analysis.sh b/bin/relationship-performance-tracking/src/generate-analysis.sh
new file mode 100755
index 00000000000..222a450d6e9
--- /dev/null
+++ b/bin/relationship-performance-tracking/src/generate-analysis.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+if [[ -z "$CONTROL_COMMIT" ]]; then
+ echo "Set the CONTROL_COMMIT env variable."
+ return 1
+fi
+
+if [[ -z "$EXPERIMENT_COMMIT" ]]; then
+ echo "Set the EXPERIMENT_COMMIT env variable."
+ return 1
+fi
+
+APP_PATH=packages/unpublished-relationship-performance-test-app
+HAR_REMIX_SCRIPT="$APP_PATH/bin/har-remix.js"
+WORKSPACE=relationship-performance-test-app
+
+git checkout $CONTROl_COMMIT
+yarn install
+yarn workspace $WORKSPACE ember build -e production --output-path dist-control
+git checkout $EXPERIMENT_COMMIT
+yarn install
+yarn workspace $WORKSPACE ember build -e production --output-path dist-experiment
+HR_PORT=4200 HR_GROUP=control pm2 start $HAR_REMIX_SCRIPT --name control
+HR_PORT=4201 HR_GROUP=experiment pm2 start $HAR_REMIX_SCRIPT --name experiment
+yarn workspace $WORKSPACE tracerbench:compare
+pm2 kill
diff --git a/bin/relationship-performance-tracking/src/head-vs-master.sh b/bin/relationship-performance-tracking/src/head-vs-master.sh
new file mode 100755
index 00000000000..39c966d2d95
--- /dev/null
+++ b/bin/relationship-performance-tracking/src/head-vs-master.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+CONTROL_COMMIT=$(git rev-parse master)
+EXPERIMENT_COMMIT=$(git rev-parse HEAD)
+./generate-analysis
\ No newline at end of file
diff --git a/package.json b/package.json
index 6df60e358d2..a3d0cf0af38 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,8 @@
"test-external:ember-data-relationship-tracker": "./bin/test-external-partner-project.js ember-data-relationship-tracker https://github.com/ef4/ember-data-relationship-tracker.git"
},
"devDependencies": {
- "@babel/plugin-transform-typescript": "^7.6.3",
+ "zlib": "1.0.5",
+ "@babel/plugin-transform-typescript": "^7.7.0",
"@ember/optional-features": "^1.1.0",
"@types/ember": "^3.1.1",
"@types/ember-qunit": "^3.4.7",
@@ -48,8 +49,8 @@
"@types/ember__test-helpers": "~0.7.9",
"@types/qunit": "^2.5.3",
"@types/rsvp": "^4.0.3",
- "@typescript-eslint/eslint-plugin": "^2.6.0",
- "@typescript-eslint/parser": "^2.6.0",
+ "@typescript-eslint/eslint-plugin": "^2.6.1",
+ "@typescript-eslint/parser": "^2.6.1",
"babel-eslint": "^10.0.3",
"babel-plugin-debug-macros": "^0.3.3",
"babel-plugin-feature-flags": "^0.3.1",
@@ -80,7 +81,7 @@
"ember-cli-inject-live-reload": "^2.0.2",
"ember-cli-internal-test-helpers": "^0.9.1",
"ember-cli-path-utils": "^1.0.0",
- "ember-cli-pretender": "^3.1.1",
+ "ember-cli-pretender": "^3.2.0",
"ember-cli-shims": "^1.2.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-string-utils": "^1.1.0",
@@ -90,7 +91,7 @@
"ember-cli-typescript-blueprints": "^3.0.0",
"ember-cli-uglify": "3.0.0",
"ember-cli-version-checker": "^3.1.2",
- "ember-cli-yuidoc": "^0.8.8",
+ "ember-cli-yuidoc": "^0.9.1",
"ember-compatibility-helpers": "^1.2.0",
"ember-decorators-polyfill": "^1.1.1",
"ember-disable-prototype-extensions": "^1.1.3",
diff --git a/packages/-ember-data/addon/-private/index.js b/packages/-ember-data/addon/-private/index.js
index 959b1e2781a..330b7802ee7 100644
--- a/packages/-ember-data/addon/-private/index.js
+++ b/packages/-ember-data/addon/-private/index.js
@@ -1,8 +1,9 @@
// public
-export { Errors, Snapshot } from '@ember-data/store/-private';
export { default as Store } from '@ember-data/store';
export { default as DS } from './core';
export { default as isEnabled } from './features';
+export { Errors } from '@ember-data/model/-private';
+export { Snapshot } from '@ember-data/store/-private';
// `ember-data-model-fragments` relies on `RootState` and `InternalModel`
// `ember-data-model-fragments' and `ember-data-change-tracker` rely on `normalizeModelName`
diff --git a/packages/-ember-data/package.json b/packages/-ember-data/package.json
index abfcaa1f4b1..4a6131b4d8b 100644
--- a/packages/-ember-data/package.json
+++ b/packages/-ember-data/package.json
@@ -38,7 +38,7 @@
"ember-inflector": "^3.0.1"
},
"devDependencies": {
- "@babel/plugin-transform-typescript": "^7.6.3",
+ "@babel/plugin-transform-typescript": "^7.7.0",
"@ember/optional-features": "^1.1.0",
"@types/ember": "^3.1.1",
"@types/ember-qunit": "^3.4.7",
@@ -60,13 +60,13 @@
"ember-cli-htmlbars": "^4.0.8",
"ember-cli-inject-live-reload": "^2.0.2",
"ember-cli-internal-test-helpers": "^0.9.1",
- "ember-cli-pretender": "^3.1.1",
+ "ember-cli-pretender": "^3.2.0",
"ember-cli-shims": "^1.2.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-test-loader": "^2.2.0",
"ember-cli-typescript-blueprints": "^3.0.0",
"ember-cli-uglify": "3.0.0",
- "ember-cli-yuidoc": "^0.8.8",
+ "ember-cli-yuidoc": "^0.9.1",
"ember-compatibility-helpers": "^1.2.0",
"ember-decorators-polyfill": "^1.1.1",
"ember-disable-prototype-extensions": "^1.1.3",
diff --git a/packages/-ember-data/tests/helpers/deprecated-test.js b/packages/-ember-data/tests/helpers/deprecated-test.js
index 25bf20ccd67..7ac5237676a 100644
--- a/packages/-ember-data/tests/helpers/deprecated-test.js
+++ b/packages/-ember-data/tests/helpers/deprecated-test.js
@@ -2,11 +2,6 @@ import { test } from 'qunit';
import VERSION from 'ember-data/version';
import { DEBUG } from '@glimmer/env';
-// temporary so that we can split out test fixes
-// from landing this. If working locally turn this
-// on to have tests fail that require being fixed.
-export const SHOULD_ASSERT_ALL = false;
-
// small comparison function for major and minor semver values
function gte(EDVersion, DeprecationVersion) {
let _edv = EDVersion.split('.');
@@ -31,12 +26,10 @@ export function deprecatedTest(testName, deprecation, testCallback) {
async function interceptor(assert) {
await testCallback.call(this, assert);
if (DEBUG) {
- if (SHOULD_ASSERT_ALL) {
- if (typeof assert.test.expected === 'number') {
- assert.test.expected += 1;
- }
- assert.expectDeprecation(deprecation);
+ if (typeof assert.test.expected === 'number') {
+ assert.test.expected += 1;
}
+ assert.expectDeprecation(deprecation);
}
}
diff --git a/packages/-ember-data/tests/helpers/qunit-asserts/assert-assertion.ts b/packages/-ember-data/tests/helpers/qunit-asserts/assert-assertion.ts
index b65acedaf85..389c91c60d8 100644
--- a/packages/-ember-data/tests/helpers/qunit-asserts/assert-assertion.ts
+++ b/packages/-ember-data/tests/helpers/qunit-asserts/assert-assertion.ts
@@ -51,17 +51,18 @@ export function configureAssertionHandler() {
label?: string
): Promise {
let outcome;
- if (DEBUG) {
- try {
- let result = cb();
- if (isThenable(result)) {
- await result;
- }
- outcome = verifyAssertion('', matcher, label);
- } catch (e) {
- outcome = verifyAssertion(e.message, matcher, label);
+
+ try {
+ let result = cb();
+ if (isThenable(result)) {
+ await result;
}
- } else {
+ outcome = verifyAssertion('', matcher, label);
+ } catch (e) {
+ outcome = verifyAssertion(e.message, matcher, label);
+ }
+
+ if (!DEBUG) {
outcome = {
result: true,
actual: '',
@@ -85,6 +86,15 @@ export function configureAssertionHandler() {
outcome = verifyNoAssertion(e.message, label);
}
+ if (!DEBUG) {
+ outcome = {
+ result: true,
+ actual: '',
+ expected: '',
+ message: `Assertions do not run in production environments`,
+ };
+ }
+
this.pushResult(outcome);
};
}
diff --git a/packages/-ember-data/tests/helpers/qunit-asserts/assert-deprecation.ts b/packages/-ember-data/tests/helpers/qunit-asserts/assert-deprecation.ts
index 5f64ae46878..24f703b3c11 100644
--- a/packages/-ember-data/tests/helpers/qunit-asserts/assert-deprecation.ts
+++ b/packages/-ember-data/tests/helpers/qunit-asserts/assert-deprecation.ts
@@ -1,5 +1,6 @@
import QUnit from 'qunit';
import { registerDeprecationHandler } from '@ember/debug';
+import { DEBUG } from '@glimmer/env';
import { checkMatcher } from './check-matcher';
import isThenable from './utils/is-thenable';
@@ -157,6 +158,16 @@ export function configureDeprecationHandler() {
}
let result = verifyDeprecation(config, label);
+
+ if (!DEBUG) {
+ result = {
+ result: true,
+ actual: { id: config.id, count: 0 },
+ expected: { id: config.id, count: 0 },
+ message: `Deprecations do not trigger in production environments`,
+ };
+ }
+
this.pushResult(result);
if (callback) {
DEPRECATIONS_FOR_TEST = origDeprecations.concat(DEPRECATIONS_FOR_TEST);
@@ -178,6 +189,16 @@ export function configureDeprecationHandler() {
}
let result = verifyNoDeprecation(filter, label);
+
+ if (!DEBUG) {
+ result = {
+ result: true,
+ actual: [],
+ expected: [],
+ message: `Deprecations do not trigger in production environments`,
+ };
+ }
+
this.pushResult(result);
DEPRECATIONS_FOR_TEST = origDeprecations.concat(DEPRECATIONS_FOR_TEST);
};
diff --git a/packages/-ember-data/tests/helpers/qunit-asserts/assert-warning.ts b/packages/-ember-data/tests/helpers/qunit-asserts/assert-warning.ts
index 51f8022fa5d..70e224601ba 100644
--- a/packages/-ember-data/tests/helpers/qunit-asserts/assert-warning.ts
+++ b/packages/-ember-data/tests/helpers/qunit-asserts/assert-warning.ts
@@ -1,5 +1,6 @@
import QUnit from 'qunit';
import { registerWarnHandler } from '@ember/debug';
+import { DEBUG } from '@glimmer/env';
import { checkMatcher } from './check-matcher';
import isThenable from './utils/is-thenable';
@@ -148,6 +149,16 @@ export function configureWarningHandler() {
}
let result = verifyWarning(config, label);
+
+ if (!DEBUG) {
+ result = {
+ result: true,
+ actual: { id: config.id, count: 0 },
+ expected: { id: config.id, count: 0 },
+ message: `Warnings do not trigger in production environments`,
+ };
+ }
+
this.pushResult(result);
WARNINGS_FOR_TEST = origWarnings.concat(WARNINGS_FOR_TEST);
};
@@ -164,6 +175,16 @@ export function configureWarningHandler() {
}
let result = verifyNoWarning(label);
+
+ if (!DEBUG) {
+ result = {
+ result: true,
+ actual: [],
+ expected: [],
+ message: `Warnings do not trigger in production environments`,
+ };
+ }
+
this.pushResult(result);
WARNINGS_FOR_TEST = origWarnings.concat(WARNINGS_FOR_TEST);
};
diff --git a/packages/-ember-data/tests/integration/application-test.js b/packages/-ember-data/tests/integration/application-test.js
index 8cc306f567c..d995b4bd3dd 100644
--- a/packages/-ember-data/tests/integration/application-test.js
+++ b/packages/-ember-data/tests/integration/application-test.js
@@ -147,6 +147,9 @@ module('integration/application - Attaching initializer', function(hooks) {
this.owner = this.application.buildInstance();
let store = this.owner.lookup('service:store');
+ assert.expectDeprecation({
+ id: 'ember-data:-legacy-test-registrations',
+ });
assert.ok(
store && store.get('isCustomStore'),
'ember-data initializer does not overwrite the previous registered service store'
diff --git a/packages/-ember-data/tests/integration/lifecycle-hooks-test.js b/packages/-ember-data/tests/integration/lifecycle-hooks-test.js
index 5015e47ca97..b1ff5c3f25c 100644
--- a/packages/-ember-data/tests/integration/lifecycle-hooks-test.js
+++ b/packages/-ember-data/tests/integration/lifecycle-hooks-test.js
@@ -57,6 +57,7 @@ module('integration/lifecycle_hooks - Lifecycle Hooks', function(hooks) {
'When the adapter acknowledges that a record has been created without a new data payload, a `didCreate` event is triggered.',
{
id: 'ember-data:evented-api-usage',
+ count: 1,
until: '4.0',
},
async function(assert) {
diff --git a/packages/-ember-data/tests/integration/record-data/record-data-errors-test.ts b/packages/-ember-data/tests/integration/record-data/record-data-errors-test.ts
index 05cab54dce1..7d30f3c0c82 100644
--- a/packages/-ember-data/tests/integration/record-data/record-data-errors-test.ts
+++ b/packages/-ember-data/tests/integration/record-data/record-data-errors-test.ts
@@ -9,6 +9,7 @@ import { JsonApiValidationError } from '@ember-data/store/-private/ts-interfaces
import RecordData from '@ember-data/store/-private/ts-interfaces/record-data';
import { RecordIdentifier } from '@ember-data/store/-private/ts-interfaces/identifier';
import { RECORD_DATA_ERRORS } from '@ember-data/canary-features';
+import JSONAPISerializer from '@ember-data/serializer/json-api';
class Person extends Model {
// TODO fix the typing for naked attrs
@@ -109,6 +110,7 @@ module('integration/record-data - Custom RecordData Errors', function(hooks) {
owner.register('model:person', Person);
owner.unregister('service:store');
owner.register('service:store', CustomStore);
+ owner.register('serializer:application', JSONAPISerializer);
});
test('Record Data invalid errors', async function(assert) {
diff --git a/packages/-ember-data/tests/integration/record-data/record-data-state-test.ts b/packages/-ember-data/tests/integration/record-data/record-data-state-test.ts
index 9ff39527c1d..1f20738b265 100644
--- a/packages/-ember-data/tests/integration/record-data/record-data-state-test.ts
+++ b/packages/-ember-data/tests/integration/record-data/record-data-state-test.ts
@@ -7,6 +7,7 @@ import { attr } from '@ember-data/model';
import Ember from 'ember';
import RecordData from '@ember-data/store/-private/ts-interfaces/record-data';
import { RECORD_DATA_STATE } from '@ember-data/canary-features';
+import JSONAPISerializer from '@ember-data/serializer/json-api';
class Person extends Model {
// TODO fix the typing for naked attrs
@@ -105,6 +106,7 @@ module('integration/record-data - Record Data State', function(hooks) {
owner.register('model:person', Person);
owner.unregister('service:store');
owner.register('service:store', CustomStore);
+ owner.register('serializer:application', JSONAPISerializer);
});
test('Record Data state saving', async function(assert) {
diff --git a/packages/-ember-data/tests/integration/relationships/has-many-test.js b/packages/-ember-data/tests/integration/relationships/has-many-test.js
index 4ecef75b41a..1424c257ffd 100644
--- a/packages/-ember-data/tests/integration/relationships/has-many-test.js
+++ b/packages/-ember-data/tests/integration/relationships/has-many-test.js
@@ -1300,6 +1300,7 @@ module('integration/relationships/has_many - Has-Many Relationships', function(h
'PromiseArray proxies evented methods to its ManyArray',
{
id: 'ember-data:evented-api-usage',
+ count: 3,
until: '4.0',
},
function(assert) {
diff --git a/packages/-ember-data/tests/integration/relationships/inverse-relationships-test.js b/packages/-ember-data/tests/integration/relationships/inverse-relationships-test.js
index 7345501d002..6d639c4b57a 100644
--- a/packages/-ember-data/tests/integration/relationships/inverse-relationships-test.js
+++ b/packages/-ember-data/tests/integration/relationships/inverse-relationships-test.js
@@ -627,7 +627,7 @@ module('integration/relationships/inverse_relationships - Inverse Relationships'
assert.expectAssertion(() => {
store.createRecord('user', { post: null });
- }, /No model was found for/);
+ }, /No model was found for 'post' and no schema handles the type/);
// but don't error if the relationship is not used
store.createRecord('user', {});
diff --git a/packages/-ember-data/tests/integration/request-state-service-test.ts b/packages/-ember-data/tests/integration/request-state-service-test.ts
index 2f3db0b98c0..de739341a88 100644
--- a/packages/-ember-data/tests/integration/request-state-service-test.ts
+++ b/packages/-ember-data/tests/integration/request-state-service-test.ts
@@ -7,6 +7,7 @@ import EmberObject from '@ember/object';
import { attr } from '@ember-data/model';
import { REQUEST_SERVICE } from '@ember-data/canary-features';
import { RequestStateEnum } from '@ember-data/store/-private/ts-interfaces/fetch-manager';
+import JSONSerializer from '@ember-data/serializer/json';
class Person extends Model {
// TODO fix the typing for naked attrs
@@ -26,6 +27,7 @@ if (REQUEST_SERVICE) {
hooks.beforeEach(function() {
let { owner } = this;
owner.register('model:person', Person);
+ owner.register('serializer:application', JSONSerializer);
store = owner.lookup('service:store');
});
diff --git a/packages/-ember-data/tests/integration/store/adapter-for-test.js b/packages/-ember-data/tests/integration/store/adapter-for-test.js
index a4db1ccd00d..1160257932e 100644
--- a/packages/-ember-data/tests/integration/store/adapter-for-test.js
+++ b/packages/-ember-data/tests/integration/store/adapter-for-test.js
@@ -42,6 +42,9 @@ module('integration/store - adapterFor', function(hooks) {
assert.expectAssertion(() => {
store.adapterFor('person');
}, /Assertion Failed: No adapter was found for 'person' and no 'application' adapter was found as a fallback/);
+ assert.expectDeprecation({
+ id: 'ember-data:-legacy-test-registrations',
+ });
});
test('we find and instantiate the application adapter', async function(assert) {
diff --git a/packages/-ember-data/tests/integration/store/serializer-for-test.js b/packages/-ember-data/tests/integration/store/serializer-for-test.js
index 1e50b793375..3aaf2c8bf7c 100644
--- a/packages/-ember-data/tests/integration/store/serializer-for-test.js
+++ b/packages/-ember-data/tests/integration/store/serializer-for-test.js
@@ -187,7 +187,8 @@ module('integration/store - serializerFor', function(hooks) {
deprecatedTest(
'we can specify a fallback serializer on the adapter when there is no application serializer',
{
- id: 'ember-data:default-serializers',
+ id: 'ember-data:default-serializer',
+ count: 1,
until: '4.0',
},
async function(assert) {
@@ -233,7 +234,7 @@ module('integration/store - serializerFor', function(hooks) {
deprecatedTest(
'specifying defaultSerializer on the application adapter when there is a per-type serializer does not work',
{
- id: 'ember-data:default-serializers',
+ id: 'ember-data:default-serializer',
until: '4.0',
},
async function(assert) {
@@ -309,7 +310,7 @@ module('integration/store - serializerFor', function(hooks) {
deprecatedTest(
'specifying defaultSerializer on a fallback adapter when there is no per-type serializer does work',
{
- id: 'ember-data:default-serializers',
+ id: 'ember-data:default-serializer',
until: '4.0',
},
async function(assert) {
@@ -374,7 +375,8 @@ module('integration/store - serializerFor', function(hooks) {
deprecatedTest(
'When the per-type, application and adapter specified fallback serializer do not exist, we fallback to the -default serializer',
{
- id: 'ember-data:default-serializers',
+ id: 'ember-data:default-serializer',
+ count: 4,
until: '4.0',
},
async function(assert) {
diff --git a/packages/-ember-data/tests/test-helper.js b/packages/-ember-data/tests/test-helper.js
index baefbda919a..16cfbb482e9 100644
--- a/packages/-ember-data/tests/test-helper.js
+++ b/packages/-ember-data/tests/test-helper.js
@@ -8,7 +8,6 @@ import { DEBUG } from '@glimmer/env';
import QUnit from 'qunit';
import { wait, asyncEqual, invokeAsync } from 'dummy/tests/helpers/async';
import configureAsserts from 'dummy/tests/helpers/qunit-asserts';
-import { SHOULD_ASSERT_ALL } from './helpers/deprecated-test';
configureAsserts();
@@ -41,9 +40,7 @@ QUnit.begin(() => {
const hooks = (mod.hooks.afterEach = mod.hooks.afterEach || []);
if (mod.tests.length !== 0) {
- if (SHOULD_ASSERT_ALL) {
- hooks.unshift(assertAllDeprecations);
- }
+ hooks.unshift(assertAllDeprecations);
}
});
}
diff --git a/packages/-ember-data/tests/unit/adapters/rest-adapter/ajax-options-test.js b/packages/-ember-data/tests/unit/adapters/rest-adapter/ajax-options-test.js
index 39ed014c433..44d7a7edab5 100644
--- a/packages/-ember-data/tests/unit/adapters/rest-adapter/ajax-options-test.js
+++ b/packages/-ember-data/tests/unit/adapters/rest-adapter/ajax-options-test.js
@@ -194,6 +194,33 @@ module('unit/adapters/rest-adapter/ajax-options - building requests', function(h
});
});
+ test('ajaxOptions() headers take precedence over adapter headers', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let adapter = store.adapterFor('application');
+
+ adapter.headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ };
+
+ let url = 'example.com';
+ let type = 'POST';
+ let ajaxOptions = adapter.ajaxOptions(url, type, {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+
+ assert.deepEqual(ajaxOptions, {
+ credentials: 'same-origin',
+ type: 'POST',
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ url: 'example.com',
+ });
+ });
+
test('_fetchRequest() returns a promise', function(assert) {
let store = this.owner.lookup('service:store');
let adapter = store.adapterFor('application');
diff --git a/packages/-ember-data/tests/unit/custom-class-support/custom-class-model-test.ts b/packages/-ember-data/tests/unit/custom-class-support/custom-class-model-test.ts
index 493b2c738ed..c5deb30f95b 100644
--- a/packages/-ember-data/tests/unit/custom-class-support/custom-class-model-test.ts
+++ b/packages/-ember-data/tests/unit/custom-class-support/custom-class-model-test.ts
@@ -54,7 +54,6 @@ if (CUSTOM_MODEL_CLASS) {
teardownRecord(record) {},
});
- owner.register('model:person', Person);
owner.register(
'adapter:application',
JSONAPIAdapter.extend({
@@ -62,7 +61,7 @@ if (CUSTOM_MODEL_CLASS) {
createRecord: () => RSVP.reject(),
})
);
- owner.register('serializer:-default', JSONAPISerializer);
+ owner.register('serializer:application', JSONAPISerializer);
owner.unregister('service:store');
});
diff --git a/packages/-ember-data/tests/unit/model-test.js b/packages/-ember-data/tests/unit/model-test.js
index 0aac3d349d6..f9b986175f1 100644
--- a/packages/-ember-data/tests/unit/model-test.js
+++ b/packages/-ember-data/tests/unit/model-test.js
@@ -1,4 +1,3 @@
-import { DEBUG } from '@glimmer/env';
import { guidFor } from '@ember/object/internals';
import { resolve, reject } from 'rsvp';
import { set, get, observer, computed } from '@ember/object';
@@ -597,6 +596,7 @@ module('unit/model - Model', function(hooks) {
'an event listener can be added to a record',
{
id: 'ember-data:evented-api-usage',
+ count: 1,
until: '4.0',
},
async function(assert) {
@@ -609,10 +609,6 @@ module('unit/model - Model', function(hooks) {
record.on('event!', F);
- if (DEBUG) {
- assert.expectDeprecation(/Called event! on person/);
- }
-
record.trigger('event!');
await settled();
@@ -631,6 +627,7 @@ module('unit/model - Model', function(hooks) {
'when an event is triggered on a record the method with the same name is invoked with arguments',
{
id: 'ember-data:evented-api-usage',
+ count: 0,
until: '4.0',
},
async function(assert) {
@@ -654,6 +651,7 @@ module('unit/model - Model', function(hooks) {
'when a method is invoked from an event with the same name the arguments are passed through',
{
id: 'ember-data:evented-api-usage',
+ count: 0,
until: '4.0',
},
async function(assert) {
@@ -915,56 +913,70 @@ module('unit/model - Model', function(hooks) {
});
module('toJSON()', function(hooks) {
- test('A Model can be JSONified', async function(assert) {
- let record = store.createRecord('person', { name: 'TomHuda' });
+ deprecatedTest(
+ 'A Model can be JSONified',
+ {
+ id: 'ember-data:model.toJSON',
+ until: '4.0',
+ },
+ async function(assert) {
+ let record = store.createRecord('person', { name: 'TomHuda' });
- assert.deepEqual(record.toJSON(), {
- data: {
- type: 'people',
- attributes: {
- name: 'TomHuda',
- 'is-archived': undefined,
- 'is-drug-addict': false,
+ assert.deepEqual(record.toJSON(), {
+ data: {
+ type: 'people',
+ attributes: {
+ name: 'TomHuda',
+ 'is-archived': undefined,
+ 'is-drug-addict': false,
+ },
},
- },
- });
- });
-
- test('toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create', async function(assert) {
- class Author extends Model {
- @hasMany('post', { async: false, inverse: 'author' })
- posts;
- }
- class Post extends Model {
- @belongsTo('author', { async: false, inverse: 'posts' })
- author;
+ });
}
- this.owner.register('model:author', Author);
- this.owner.register('model:post', Post);
+ );
- // Loading the person without explicitly
- // loading its relationships seems to trigger the
- // original bug where `this.store` was not
- // present on the serializer due to using .create
- // instead of `store.serializerFor`.
- let person = store.push({
- data: {
- type: 'author',
- id: '1',
- },
- });
+ deprecatedTest(
+ 'toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create',
+ {
+ id: 'ember-data:model.toJSON',
+ until: '4.0',
+ },
+ async function(assert) {
+ class Author extends Model {
+ @hasMany('post', { async: false, inverse: 'author' })
+ posts;
+ }
+ class Post extends Model {
+ @belongsTo('author', { async: false, inverse: 'posts' })
+ author;
+ }
+ this.owner.register('model:author', Author);
+ this.owner.register('model:post', Post);
+
+ // Loading the person without explicitly
+ // loading its relationships seems to trigger the
+ // original bug where `this.store` was not
+ // present on the serializer due to using .create
+ // instead of `store.serializerFor`.
+ let person = store.push({
+ data: {
+ type: 'author',
+ id: '1',
+ },
+ });
- let errorThrown = false;
- let json;
- try {
- json = person.toJSON();
- } catch (e) {
- errorThrown = true;
- }
+ let errorThrown = false;
+ let json;
+ try {
+ json = person.toJSON();
+ } catch (e) {
+ errorThrown = true;
+ }
- assert.ok(!errorThrown, 'error not thrown due to missing store');
- assert.deepEqual(json, { data: { type: 'authors' } });
- });
+ assert.ok(!errorThrown, 'error not thrown due to missing store');
+ assert.deepEqual(json, { data: { type: 'authors' } });
+ }
+ );
});
module('Updating', function() {
diff --git a/packages/-ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/-ember-data/tests/unit/model/lifecycle-callbacks-test.js
index 3b2c982636a..ae73779a894 100644
--- a/packages/-ember-data/tests/unit/model/lifecycle-callbacks-test.js
+++ b/packages/-ember-data/tests/unit/model/lifecycle-callbacks-test.js
@@ -3,299 +3,349 @@ import { get } from '@ember/object';
import { run } from '@ember/runloop';
import { setupTest } from 'ember-qunit';
-import { module, test } from 'qunit';
+import { module } from 'qunit';
import Adapter from '@ember-data/adapter';
import JSONAPISerializer from '@ember-data/serializer/json-api';
import Model, { attr } from '@ember-data/model';
import { InvalidError } from '@ember-data/adapter/error';
+import { deprecatedTest } from '../../helpers/deprecated-test';
module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function(hooks) {
setupTest(hooks);
- test('a record receives a didLoad callback when it has finished loading', function(assert) {
- assert.expect(3);
-
- const Person = Model.extend({
- name: attr(),
- didLoad() {
- assert.ok('The didLoad callback was called');
- },
- });
+ deprecatedTest(
+ 'a record receives a didLoad callback when it has finished loading',
+ {
+ id: 'ember-data:record-lifecycle-event-methods',
+ until: '4.0',
+ },
+ function(assert) {
+ assert.expect(3);
+
+ const Person = Model.extend({
+ name: attr(),
+ didLoad() {
+ assert.ok('The didLoad callback was called');
+ },
+ });
- const ApplicationAdapter = Adapter.extend({
- findRecord(store, type, id, snapshot) {
- return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } };
- },
- });
+ const ApplicationAdapter = Adapter.extend({
+ findRecord(store, type, id, snapshot) {
+ return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } };
+ },
+ });
- this.owner.register('model:person', Person);
- this.owner.register('adapter:application', ApplicationAdapter);
- this.owner.register('serializer:application', JSONAPISerializer.extend());
+ this.owner.register('model:person', Person);
+ this.owner.register('adapter:application', ApplicationAdapter);
+ this.owner.register('serializer:application', JSONAPISerializer.extend());
- let store = this.owner.lookup('service:store');
+ let store = this.owner.lookup('service:store');
- return run(() => {
- return store.findRecord('person', 1).then(person => {
- assert.equal(person.get('id'), '1', `The person's ID is available`);
- assert.equal(person.get('name'), 'Foo', `The person's properties are availablez`);
+ return run(() => {
+ return store.findRecord('person', 1).then(person => {
+ assert.equal(person.get('id'), '1', `The person's ID is available`);
+ assert.equal(person.get('name'), 'Foo', `The person's properties are availablez`);
+ });
+ });
+ }
+ );
+
+ deprecatedTest(
+ `a record receives a didLoad callback once it materializes if it wasn't materialized when loaded`,
+ {
+ id: 'ember-data:record-lifecycle-event-methods',
+ until: '4.0',
+ },
+ function(assert) {
+ assert.expect(2);
+
+ let didLoadCalled = 0;
+ const Person = Model.extend({
+ name: attr(),
+ didLoad() {
+ didLoadCalled++;
+ },
});
- });
- });
-
- test(`TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded`, function(assert) {
- assert.expect(2);
-
- let didLoadCalled = 0;
- const Person = Model.extend({
- name: attr(),
- didLoad() {
- didLoadCalled++;
- },
- });
- this.owner.register('model:person', Person);
+ this.owner.register('model:person', Person);
- let store = this.owner.lookup('service:store');
+ let store = this.owner.lookup('service:store');
- run(() => {
- store._pushInternalModel({ id: 1, type: 'person' });
- assert.equal(didLoadCalled, 0, 'didLoad was not called');
- });
+ run(() => {
+ store._pushInternalModel({ id: 1, type: 'person' });
+ assert.equal(didLoadCalled, 0, 'didLoad was not called');
+ });
- run(() => store.peekRecord('person', 1));
+ run(() => store.peekRecord('person', 1));
- assert.equal(didLoadCalled, 1, 'didLoad was called');
- });
+ assert.equal(didLoadCalled, 1, 'didLoad was called');
+ }
+ );
- test('a record receives a didUpdate callback when it has finished updating', function(assert) {
- assert.expect(5);
+ deprecatedTest(
+ 'a record receives a didUpdate callback when it has finished updating',
+ {
+ id: 'ember-data:record-lifecycle-event-methods',
+ until: '4.0',
+ },
+ function(assert) {
+ assert.expect(5);
- let callCount = 0;
+ let callCount = 0;
- const Person = Model.extend({
- bar: attr('string'),
- name: attr('string'),
+ const Person = Model.extend({
+ bar: attr('string'),
+ name: attr('string'),
- didUpdate() {
- callCount++;
- assert.equal(get(this, 'isSaving'), false, 'record should be saving');
- assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty');
- },
- });
+ didUpdate() {
+ callCount++;
+ assert.equal(get(this, 'isSaving'), false, 'record should be saving');
+ assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty');
+ },
+ });
- const ApplicationAdapter = Adapter.extend({
- findRecord(store, type, id, snapshot) {
- return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } };
- },
+ const ApplicationAdapter = Adapter.extend({
+ findRecord(store, type, id, snapshot) {
+ return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } };
+ },
- updateRecord(store, type, snapshot) {
- assert.equal(callCount, 0, 'didUpdate callback was not called until didSaveRecord is called');
- return resolve();
- },
- });
+ updateRecord(store, type, snapshot) {
+ assert.equal(callCount, 0, 'didUpdate callback was not called until didSaveRecord is called');
+ return resolve();
+ },
+ });
- this.owner.register('model:person', Person);
- this.owner.register('adapter:application', ApplicationAdapter);
- this.owner.register('serializer:application', JSONAPISerializer.extend());
+ this.owner.register('model:person', Person);
+ this.owner.register('adapter:application', ApplicationAdapter);
+ this.owner.register('serializer:application', JSONAPISerializer.extend());
- let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1));
+ let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1));
- assert.equal(callCount, 0, 'precond - didUpdate callback was not called yet');
+ assert.equal(callCount, 0, 'precond - didUpdate callback was not called yet');
- return run(() => {
- return asyncPerson
- .then(person => {
- return run(() => {
- person.set('bar', 'Bar');
- return person.save();
+ return run(() => {
+ return asyncPerson
+ .then(person => {
+ return run(() => {
+ person.set('bar', 'Bar');
+ return person.save();
+ });
+ })
+ .then(() => {
+ assert.equal(callCount, 1, 'didUpdate called after update');
});
- })
- .then(() => {
- assert.equal(callCount, 1, 'didUpdate called after update');
- });
- });
- });
-
- test('a record receives a didCreate callback when it has finished updating', function(assert) {
- assert.expect(5);
-
- let callCount = 0;
-
- const Person = Model.extend({
- didCreate() {
- callCount++;
- assert.equal(get(this, 'isSaving'), false, 'record should not be saving');
- assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty');
- },
- });
-
- const ApplicationAdapter = Adapter.extend({
- createRecord(store, type, snapshot) {
- assert.equal(callCount, 0, 'didCreate callback was not called until didSaveRecord is called');
- return resolve();
- },
- });
-
- this.owner.register('model:person', Person);
- this.owner.register('adapter:application', ApplicationAdapter);
- this.owner.register('serializer:application', JSONAPISerializer.extend());
-
- assert.equal(callCount, 0, 'precond - didCreate callback was not called yet');
-
- let person = this.owner.lookup('service:store').createRecord('person', {
- id: 69,
- name: 'Newt Gingrich',
- });
-
- return run(() => {
- return person.save().then(() => {
- assert.equal(callCount, 1, 'didCreate called after commit');
});
- });
- });
+ }
+ );
+
+ deprecatedTest(
+ 'a record receives a didCreate callback when it has finished updating',
+ {
+ id: 'ember-data:record-lifecycle-event-methods',
+ until: '4.0',
+ },
+ function(assert) {
+ assert.expect(5);
+
+ let callCount = 0;
+
+ const Person = Model.extend({
+ didCreate() {
+ callCount++;
+ assert.equal(get(this, 'isSaving'), false, 'record should not be saving');
+ assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty');
+ },
+ });
- test('a record receives a didDelete callback when it has finished deleting', function(assert) {
- assert.expect(5);
+ const ApplicationAdapter = Adapter.extend({
+ createRecord(store, type, snapshot) {
+ assert.equal(callCount, 0, 'didCreate callback was not called until didSaveRecord is called');
+ return resolve();
+ },
+ });
- let callCount = 0;
+ this.owner.register('model:person', Person);
+ this.owner.register('adapter:application', ApplicationAdapter);
+ this.owner.register('serializer:application', JSONAPISerializer.extend());
- const Person = Model.extend({
- bar: attr('string'),
- name: attr('string'),
+ assert.equal(callCount, 0, 'precond - didCreate callback was not called yet');
- didDelete() {
- callCount++;
+ let person = this.owner.lookup('service:store').createRecord('person', {
+ id: 69,
+ name: 'Newt Gingrich',
+ });
- assert.equal(get(this, 'isSaving'), false, 'record should not be saving');
- assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty');
- },
- });
+ return run(() => {
+ return person.save().then(() => {
+ assert.equal(callCount, 1, 'didCreate called after commit');
+ });
+ });
+ }
+ );
+
+ deprecatedTest(
+ 'a record receives a didDelete callback when it has finished deleting',
+ {
+ id: 'ember-data:record-lifecycle-event-methods',
+ until: '4.0',
+ },
+ function(assert) {
+ assert.expect(5);
+
+ let callCount = 0;
+
+ const Person = Model.extend({
+ bar: attr('string'),
+ name: attr('string'),
+
+ didDelete() {
+ callCount++;
+
+ assert.equal(get(this, 'isSaving'), false, 'record should not be saving');
+ assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty');
+ },
+ });
- const ApplicationAdapter = Adapter.extend({
- findRecord(store, type, id, snapshot) {
- return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } };
- },
+ const ApplicationAdapter = Adapter.extend({
+ findRecord(store, type, id, snapshot) {
+ return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } };
+ },
- deleteRecord(store, type, snapshot) {
- assert.equal(callCount, 0, 'didDelete callback was not called until didSaveRecord is called');
+ deleteRecord(store, type, snapshot) {
+ assert.equal(callCount, 0, 'didDelete callback was not called until didSaveRecord is called');
- return resolve();
- },
- });
+ return resolve();
+ },
+ });
- this.owner.register('model:person', Person);
- this.owner.register('adapter:application', ApplicationAdapter);
- this.owner.register('serializer:application', JSONAPISerializer.extend());
+ this.owner.register('model:person', Person);
+ this.owner.register('adapter:application', ApplicationAdapter);
+ this.owner.register('serializer:application', JSONAPISerializer.extend());
- let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1));
+ let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1));
- assert.equal(callCount, 0, 'precond - didDelete callback was not called yet');
+ assert.equal(callCount, 0, 'precond - didDelete callback was not called yet');
- return run(() => {
- return asyncPerson
- .then(person => {
- return run(() => {
- person.deleteRecord();
- return person.save();
+ return run(() => {
+ return asyncPerson
+ .then(person => {
+ return run(() => {
+ person.deleteRecord();
+ return person.save();
+ });
+ })
+ .then(() => {
+ assert.equal(callCount, 1, 'didDelete called after delete');
});
- })
- .then(() => {
- assert.equal(callCount, 1, 'didDelete called after delete');
- });
- });
- });
-
- test('an uncommited record also receives a didDelete callback when it is deleted', function(assert) {
- assert.expect(4);
-
- let callCount = 0;
+ });
+ }
+ );
+
+ deprecatedTest(
+ 'an uncommited record also receives a didDelete callback when it is deleted',
+ {
+ id: 'ember-data:record-lifecycle-event-methods',
+ until: '4.0',
+ },
+ function(assert) {
+ assert.expect(4);
+
+ let callCount = 0;
+
+ const Person = Model.extend({
+ bar: attr('string'),
+ name: attr('string'),
+
+ didDelete() {
+ callCount++;
+ assert.equal(get(this, 'isSaving'), false, 'record should not be saving');
+ assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty');
+ },
+ });
- const Person = Model.extend({
- bar: attr('string'),
- name: attr('string'),
+ this.owner.register('model:person', Person);
- didDelete() {
- callCount++;
- assert.equal(get(this, 'isSaving'), false, 'record should not be saving');
- assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty');
- },
- });
+ let person = this.owner.lookup('service:store').createRecord('person', {
+ name: 'Tomster',
+ });
- this.owner.register('model:person', Person);
+ assert.equal(callCount, 0, 'precond - didDelete callback was not called yet');
- let person = this.owner.lookup('service:store').createRecord('person', {
- name: 'Tomster',
- });
+ run(() => person.deleteRecord());
- assert.equal(callCount, 0, 'precond - didDelete callback was not called yet');
+ assert.equal(callCount, 1, 'didDelete called after delete');
+ }
+ );
- run(() => person.deleteRecord());
+ deprecatedTest(
+ 'a record receives a becameInvalid callback when it became invalid',
+ {
+ id: 'ember-data:record-lifecycle-event-methods',
+ until: '4.0',
+ },
+ function(assert) {
+ assert.expect(8);
- assert.equal(callCount, 1, 'didDelete called after delete');
- });
+ let callCount = 0;
- test('a record receives a becameInvalid callback when it became invalid', function(assert) {
- assert.expect(8);
+ const Person = Model.extend({
+ bar: attr('string'),
+ name: attr('string'),
- let callCount = 0;
+ becameInvalid() {
+ callCount++;
- const Person = Model.extend({
- bar: attr('string'),
- name: attr('string'),
+ assert.equal(get(this, 'isSaving'), false, 'record should not be saving');
+ assert.equal(get(this, 'hasDirtyAttributes'), true, 'record should be dirty');
+ },
+ });
- becameInvalid() {
- callCount++;
+ const ApplicationAdapter = Adapter.extend({
+ findRecord(store, type, id, snapshot) {
+ return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } };
+ },
+
+ updateRecord(store, type, snapshot) {
+ assert.equal(callCount, 0, 'becameInvalid callback was not called until recordWasInvalid is called');
+
+ return reject(
+ new InvalidError([
+ {
+ title: 'Invalid Attribute',
+ detail: 'error',
+ source: {
+ pointer: '/data/attributes/bar',
+ },
+ },
+ ])
+ );
+ },
+ });
- assert.equal(get(this, 'isSaving'), false, 'record should not be saving');
- assert.equal(get(this, 'hasDirtyAttributes'), true, 'record should be dirty');
- },
- });
+ this.owner.register('model:person', Person);
+ this.owner.register('adapter:application', ApplicationAdapter);
+ this.owner.register('serializer:application', JSONAPISerializer.extend());
- const ApplicationAdapter = Adapter.extend({
- findRecord(store, type, id, snapshot) {
- return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } };
- },
+ let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1));
+ assert.equal(callCount, 0, 'precond - becameInvalid callback was not called yet');
- updateRecord(store, type, snapshot) {
- assert.equal(callCount, 0, 'becameInvalid callback was not called until recordWasInvalid is called');
+ // Make sure that the error handler has a chance to attach before
+ // save fails.
+ return run(() => {
+ return asyncPerson.then(person => {
+ return run(() => {
+ person.set('bar', 'Bar');
+ return person.save().catch(reason => {
+ assert.ok(reason.isAdapterError, 'reason should have been an adapter error');
- return reject(
- new InvalidError([
- {
- title: 'Invalid Attribute',
- detail: 'error',
- source: {
- pointer: '/data/attributes/bar',
- },
- },
- ])
- );
- },
- });
-
- this.owner.register('model:person', Person);
- this.owner.register('adapter:application', ApplicationAdapter);
- this.owner.register('serializer:application', JSONAPISerializer.extend());
-
- let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1));
- assert.equal(callCount, 0, 'precond - becameInvalid callback was not called yet');
-
- // Make sure that the error handler has a chance to attach before
- // save fails.
- return run(() => {
- return asyncPerson.then(person => {
- return run(() => {
- person.set('bar', 'Bar');
- return person.save().catch(reason => {
- assert.ok(reason.isAdapterError, 'reason should have been an adapter error');
-
- assert.equal(reason.errors.length, 1, 'reason should have one error');
- assert.equal(reason.errors[0].title, 'Invalid Attribute');
- assert.equal(callCount, 1, 'becameInvalid called after invalidating');
+ assert.equal(reason.errors.length, 1, 'reason should have one error');
+ assert.equal(reason.errors[0].title, 'Invalid Attribute');
+ assert.equal(callCount, 1, 'becameInvalid called after invalidating');
+ });
});
});
});
- });
- });
+ }
+ );
});
diff --git a/packages/-ember-data/tests/unit/model/rollback-attributes-test.js b/packages/-ember-data/tests/unit/model/rollback-attributes-test.js
index deaefb6008e..c670fac01d7 100644
--- a/packages/-ember-data/tests/unit/model/rollback-attributes-test.js
+++ b/packages/-ember-data/tests/unit/model/rollback-attributes-test.js
@@ -18,450 +18,451 @@ import { settled } from '@ember/test-helpers';
module('unit/model/rollbackAttributes - model.rollbackAttributes()', function(hooks) {
setupTest(hooks);
- hooks.beforeEach(function() {
- const Person = DS.Model.extend({
- firstName: DS.attr(),
- lastName: DS.attr(),
- rolledBackCount: 0,
- rolledBack() {
- this.incrementProperty('rolledBackCount');
- },
- });
- Person.reopenClass({
- toString() {
- return 'Person';
- },
- });
-
- this.owner.register('model:person', Person);
- this.owner.register('adapter:application', Adapter.extend());
- this.owner.register('serializer:application', JSONAPISerializer.extend());
- });
-
- test('changes to attributes can be rolled back', function(assert) {
- let store = this.owner.lookup('service:store');
- let person;
-
- run(() => {
- store.push({
- data: {
- type: 'person',
- id: '1',
- attributes: {
- firstName: 'Tom',
- lastName: 'Dale',
- },
+ module('rolledBack hook', function(hooks) {
+ hooks.beforeEach(function() {
+ const Person = DS.Model.extend({
+ firstName: DS.attr(),
+ lastName: DS.attr(),
+ rolledBackCount: 0,
+ rolledBack() {
+ this.incrementProperty('rolledBackCount');
},
});
- person = store.peekRecord('person', 1);
- person.set('firstName', 'Thomas');
- return person;
- });
-
- assert.equal(person.get('firstName'), 'Thomas');
- assert.equal(person.get('rolledBackCount'), 0);
-
- run(() => person.rollbackAttributes());
-
- assert.equal(person.get('firstName'), 'Tom');
- assert.equal(person.get('hasDirtyAttributes'), false);
- assert.equal(person.get('rolledBackCount'), 1);
- });
-
- test('changes to unassigned attributes can be rolled back', function(assert) {
- let store = this.owner.lookup('service:store');
- let person;
-
- run(() => {
- store.push({
- data: {
- type: 'person',
- id: '1',
- attributes: {
- lastName: 'Dale',
- },
+ Person.reopenClass({
+ toString() {
+ return 'Person';
},
});
- person = store.peekRecord('person', 1);
- person.set('firstName', 'Thomas');
- return person;
+ this.owner.register('model:person', Person);
+ this.owner.register('adapter:application', Adapter.extend());
+ this.owner.register('serializer:application', JSONAPISerializer.extend());
+ });
+ hooks.afterEach(function(assert) {
+ assert.expectDeprecation({
+ id: 'ember-data:record-lifecycle-event-methods',
+ });
});
- assert.equal(person.get('firstName'), 'Thomas');
- assert.equal(person.get('rolledBackCount'), 0);
-
- run(() => person.rollbackAttributes());
-
- assert.strictEqual(person.get('firstName'), undefined);
- assert.equal(person.get('hasDirtyAttributes'), false);
- assert.equal(person.get('rolledBackCount'), 1);
- });
-
- test('changes to attributes made after a record is in-flight only rolls back the local changes', function(assert) {
- let store = this.owner.lookup('service:store');
- let adapter = store.adapterFor('application');
-
- adapter.updateRecord = function(store, type, snapshot) {
- // Make sure the save is async
- return new EmberPromise(resolve => later(null, resolve, 15));
- };
-
- let person = run(() => {
- store.push({
- data: {
- type: 'person',
- id: '1',
- attributes: {
- firstName: 'Tom',
- lastName: 'Dale',
+ test('changes to attributes can be rolled back', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let person;
+
+ run(() => {
+ store.push({
+ data: {
+ type: 'person',
+ id: '1',
+ attributes: {
+ firstName: 'Tom',
+ lastName: 'Dale',
+ },
},
- },
+ });
+ person = store.peekRecord('person', 1);
+ person.set('firstName', 'Thomas');
+ return person;
});
- let person = store.peekRecord('person', 1);
- person.set('firstName', 'Thomas');
+ assert.equal(person.get('firstName'), 'Thomas');
+ assert.equal(person.get('rolledBackCount'), 0);
- return person;
- });
+ run(() => person.rollbackAttributes());
- return run(() => {
- let saving = person.save();
+ assert.equal(person.get('firstName'), 'Tom');
+ assert.equal(person.get('hasDirtyAttributes'), false);
+ assert.equal(person.get('rolledBackCount'), 1);
+ });
- assert.equal(person.get('firstName'), 'Thomas');
+ test('changes to unassigned attributes can be rolled back', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let person;
+
+ run(() => {
+ store.push({
+ data: {
+ type: 'person',
+ id: '1',
+ attributes: {
+ lastName: 'Dale',
+ },
+ },
+ });
+ person = store.peekRecord('person', 1);
+ person.set('firstName', 'Thomas');
- person.set('lastName', 'Dolly');
+ return person;
+ });
- assert.equal(person.get('lastName'), 'Dolly');
+ assert.equal(person.get('firstName'), 'Thomas');
assert.equal(person.get('rolledBackCount'), 0);
- person.rollbackAttributes();
+ run(() => person.rollbackAttributes());
- assert.equal(person.get('firstName'), 'Thomas');
- assert.equal(person.get('lastName'), 'Dale');
- assert.equal(person.get('isSaving'), true);
-
- return saving.then(() => {
- assert.equal(person.get('rolledBackCount'), 1);
- assert.equal(person.get('hasDirtyAttributes'), false, 'The person is now clean');
- });
+ assert.strictEqual(person.get('firstName'), undefined);
+ assert.equal(person.get('hasDirtyAttributes'), false);
+ assert.equal(person.get('rolledBackCount'), 1);
});
- });
- test("a record's changes can be made if it fails to save", function(assert) {
- let store = this.owner.lookup('service:store');
- let adapter = store.adapterFor('application');
+ test('changes to attributes made after a record is in-flight only rolls back the local changes', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let adapter = store.adapterFor('application');
+
+ adapter.updateRecord = function(store, type, snapshot) {
+ // Make sure the save is async
+ return new EmberPromise(resolve => later(null, resolve, 15));
+ };
+
+ let person = run(() => {
+ store.push({
+ data: {
+ type: 'person',
+ id: '1',
+ attributes: {
+ firstName: 'Tom',
+ lastName: 'Dale',
+ },
+ },
+ });
- adapter.updateRecord = function(store, type, snapshot) {
- return reject();
- };
+ let person = store.peekRecord('person', 1);
+ person.set('firstName', 'Thomas');
- let person = run(() => {
- store.push({
- data: {
- type: 'person',
- id: '1',
- attributes: {
- firstName: 'Tom',
- lastName: 'Dale',
- },
- },
+ return person;
});
- let person = store.peekRecord('person', 1);
- person.set('firstName', 'Thomas');
+ return run(() => {
+ let saving = person.save();
- return person;
- });
+ assert.equal(person.get('firstName'), 'Thomas');
- assert.deepEqual(person.changedAttributes().firstName, ['Tom', 'Thomas']);
+ person.set('lastName', 'Dolly');
- run(function() {
- person.save().then(null, function() {
- assert.equal(person.get('isError'), true);
- assert.deepEqual(person.changedAttributes().firstName, ['Tom', 'Thomas']);
+ assert.equal(person.get('lastName'), 'Dolly');
assert.equal(person.get('rolledBackCount'), 0);
- run(function() {
- person.rollbackAttributes();
- });
+ person.rollbackAttributes();
+
+ assert.equal(person.get('firstName'), 'Thomas');
+ assert.equal(person.get('lastName'), 'Dale');
+ assert.equal(person.get('isSaving'), true);
- assert.equal(person.get('firstName'), 'Tom');
- assert.equal(person.get('isError'), false);
- assert.equal(Object.keys(person.changedAttributes()).length, 0);
- assert.equal(person.get('rolledBackCount'), 1);
+ return saving.then(() => {
+ assert.equal(person.get('rolledBackCount'), 1);
+ assert.equal(person.get('hasDirtyAttributes'), false, 'The person is now clean');
+ });
});
});
- });
-
- test(`a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly`, function(assert) {
- assert.expect(10);
- let store = this.owner.lookup('service:store');
- let adapter = store.adapterFor('application');
-
- adapter.deleteRecord = function(store, type, snapshot) {
- return reject();
- };
+ test("a record's changes can be made if it fails to save", function(assert) {
+ let store = this.owner.lookup('service:store');
+ let adapter = store.adapterFor('application');
+
+ adapter.updateRecord = function(store, type, snapshot) {
+ return reject();
+ };
+
+ let person = run(() => {
+ store.push({
+ data: {
+ type: 'person',
+ id: '1',
+ attributes: {
+ firstName: 'Tom',
+ lastName: 'Dale',
+ },
+ },
+ });
- let person, people;
+ let person = store.peekRecord('person', 1);
+ person.set('firstName', 'Thomas');
- run(() => {
- store.push({
- data: {
- type: 'person',
- id: '1',
- attributes: {
- firstName: 'Tom',
- lastName: 'Dale',
- },
- },
+ return person;
});
- person = store.peekRecord('person', 1);
- people = store.peekAll('person');
- });
- run(() => person.deleteRecord());
+ assert.deepEqual(person.changedAttributes().firstName, ['Tom', 'Thomas']);
- assert.equal(people.get('length'), 1, 'a deleted record appears in record array until it is saved');
- assert.equal(people.objectAt(0), person, 'a deleted record appears in record array until it is saved');
-
- return run(() => {
- return person
- .save()
- .catch(() => {
+ run(function() {
+ person.save().then(null, function() {
assert.equal(person.get('isError'), true);
- assert.equal(person.get('isDeleted'), true);
+ assert.deepEqual(person.changedAttributes().firstName, ['Tom', 'Thomas']);
assert.equal(person.get('rolledBackCount'), 0);
- run(() => person.rollbackAttributes());
+ run(function() {
+ person.rollbackAttributes();
+ });
- assert.equal(person.get('isDeleted'), false);
+ assert.equal(person.get('firstName'), 'Tom');
assert.equal(person.get('isError'), false);
- assert.equal(person.get('hasDirtyAttributes'), false, 'must be not dirty');
+ assert.equal(Object.keys(person.changedAttributes()).length, 0);
assert.equal(person.get('rolledBackCount'), 1);
- })
- .then(() => {
- assert.equal(
- people.get('length'),
- 1,
- 'the underlying record array is updated accordingly in an asynchronous way'
- );
});
+ });
});
- });
- test(`new record's attributes can be rollbacked`, function(assert) {
- let store = this.owner.lookup('service:store');
- let person = store.createRecord('person', { id: 1 });
+ test(`a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly`, function(assert) {
+ let store = this.owner.lookup('service:store');
+ let adapter = store.adapterFor('application');
+
+ adapter.deleteRecord = function(store, type, snapshot) {
+ return reject();
+ };
+
+ let person, people;
+
+ run(() => {
+ store.push({
+ data: {
+ type: 'person',
+ id: '1',
+ attributes: {
+ firstName: 'Tom',
+ lastName: 'Dale',
+ },
+ },
+ });
+ person = store.peekRecord('person', 1);
+ people = store.peekAll('person');
+ });
- assert.equal(person.get('isNew'), true, 'must be new');
- assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty');
- assert.equal(person.get('rolledBackCount'), 0);
+ run(() => person.deleteRecord());
+
+ assert.equal(people.get('length'), 1, 'a deleted record appears in record array until it is saved');
+ assert.equal(people.objectAt(0), person, 'a deleted record appears in record array until it is saved');
+
+ return run(() => {
+ return person
+ .save()
+ .catch(() => {
+ assert.equal(person.get('isError'), true);
+ assert.equal(person.get('isDeleted'), true);
+ assert.equal(person.get('rolledBackCount'), 0);
+
+ run(() => person.rollbackAttributes());
+
+ assert.equal(person.get('isDeleted'), false);
+ assert.equal(person.get('isError'), false);
+ assert.equal(person.get('hasDirtyAttributes'), false, 'must be not dirty');
+ assert.equal(person.get('rolledBackCount'), 1);
+ })
+ .then(() => {
+ assert.equal(
+ people.get('length'),
+ 1,
+ 'the underlying record array is updated accordingly in an asynchronous way'
+ );
+ });
+ });
+ });
- run(person, 'rollbackAttributes');
+ test(`new record's attributes can be rollbacked`, function(assert) {
+ let store = this.owner.lookup('service:store');
+ let person = store.createRecord('person', { id: 1 });
- assert.equal(person.get('isNew'), false, 'must not be new');
- assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty');
- assert.equal(person.get('isDeleted'), true, 'must be deleted');
- assert.equal(person.get('rolledBackCount'), 1);
- });
+ assert.equal(person.get('isNew'), true, 'must be new');
+ assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty');
+ assert.equal(person.get('rolledBackCount'), 0);
- test(`invalid new record's attributes can be rollbacked`, function(assert) {
- let error = new DS.InvalidError([
- {
- detail: 'is invalid',
- source: { pointer: 'data/attributes/name' },
- },
- ]);
+ run(person, 'rollbackAttributes');
- let adapter = DS.RESTAdapter.extend({
- ajax(url, type, hash) {
- return reject(error);
- },
+ assert.equal(person.get('isNew'), false, 'must not be new');
+ assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty');
+ assert.equal(person.get('isDeleted'), true, 'must be deleted');
+ assert.equal(person.get('rolledBackCount'), 1);
});
- this.owner.register('adapter:application', adapter);
- this.owner.register('serializer:application', RESTSerializer.extend());
+ test(`invalid new record's attributes can be rollbacked`, function(assert) {
+ let error = new DS.InvalidError([
+ {
+ detail: 'is invalid',
+ source: { pointer: 'data/attributes/name' },
+ },
+ ]);
- let store = this.owner.lookup('service:store');
- let person = store.createRecord('person', { id: 1 });
+ let adapter = DS.RESTAdapter.extend({
+ ajax(url, type, hash) {
+ return reject(error);
+ },
+ });
- assert.equal(person.get('isNew'), true, 'must be new');
- assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty');
+ this.owner.register('adapter:application', adapter);
+ this.owner.register('serializer:application', RESTSerializer.extend());
- return run(() => {
- return person.save().catch(reason => {
- assert.equal(error, reason);
- assert.equal(person.get('isValid'), false);
+ let store = this.owner.lookup('service:store');
+ let person = store.createRecord('person', { id: 1 });
- run(() => person.rollbackAttributes());
+ assert.equal(person.get('isNew'), true, 'must be new');
+ assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty');
- assert.equal(person.get('isNew'), false, 'must not be new');
- assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty');
- assert.equal(person.get('isDeleted'), true, 'must be deleted');
- assert.equal(person.get('rolledBackCount'), 1);
- });
- });
- });
+ return run(() => {
+ return person.save().catch(reason => {
+ assert.equal(error, reason);
+ assert.equal(person.get('isValid'), false);
- test(`invalid record's attributes can be rollbacked after multiple failed calls - #3677`, function(assert) {
- let adapter = DS.RESTAdapter.extend({
- ajax(url, type, hash) {
- let error = new DS.InvalidError();
- return reject(error);
- },
- });
-
- this.owner.register('adapter:application', adapter);
- this.owner.register('serializer:application', RESTSerializer.extend());
+ run(() => person.rollbackAttributes());
- let store = this.owner.lookup('service:store');
+ assert.equal(person.get('isNew'), false, 'must not be new');
+ assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty');
+ assert.equal(person.get('isDeleted'), true, 'must be deleted');
+ assert.equal(person.get('rolledBackCount'), 1);
+ });
+ });
+ });
- let person;
- run(() => {
- person = store.push({
- data: {
- type: 'person',
- id: 1,
- attributes: {
- firstName: 'original name',
- },
+ test(`invalid record's attributes can be rollbacked after multiple failed calls - #3677`, function(assert) {
+ let adapter = DS.RESTAdapter.extend({
+ ajax(url, type, hash) {
+ let error = new DS.InvalidError();
+ return reject(error);
},
});
- person.set('firstName', 'updated name');
- });
+ this.owner.register('adapter:application', adapter);
+ this.owner.register('serializer:application', RESTSerializer.extend());
- return run(() => {
- assert.equal(person.get('firstName'), 'updated name', 'precondition: firstName is changed');
+ let store = this.owner.lookup('service:store');
- return person
- .save()
- .catch(() => {
- assert.equal(person.get('hasDirtyAttributes'), true, 'has dirty attributes');
- assert.equal(person.get('firstName'), 'updated name', 'firstName is still changed');
+ let person;
+ run(() => {
+ person = store.push({
+ data: {
+ type: 'person',
+ id: 1,
+ attributes: {
+ firstName: 'original name',
+ },
+ },
+ });
- return person.save();
- })
- .catch(() => {
- run(() => person.rollbackAttributes());
+ person.set('firstName', 'updated name');
+ });
- assert.equal(person.get('hasDirtyAttributes'), false, 'has no dirty attributes');
- assert.equal(
- person.get('firstName'),
- 'original name',
- 'after rollbackAttributes() firstName has the original value'
- );
- assert.equal(person.get('rolledBackCount'), 1);
- });
+ return run(() => {
+ assert.equal(person.get('firstName'), 'updated name', 'precondition: firstName is changed');
+
+ return person
+ .save()
+ .catch(() => {
+ assert.equal(person.get('hasDirtyAttributes'), true, 'has dirty attributes');
+ assert.equal(person.get('firstName'), 'updated name', 'firstName is still changed');
+
+ return person.save();
+ })
+ .catch(() => {
+ run(() => person.rollbackAttributes());
+
+ assert.equal(person.get('hasDirtyAttributes'), false, 'has no dirty attributes');
+ assert.equal(
+ person.get('firstName'),
+ 'original name',
+ 'after rollbackAttributes() firstName has the original value'
+ );
+ assert.equal(person.get('rolledBackCount'), 1);
+ });
+ });
});
- });
- test(`deleted record's attributes can be rollbacked`, function(assert) {
- let store = this.owner.lookup('service:store');
+ test(`deleted record's attributes can be rollbacked`, function(assert) {
+ let store = this.owner.lookup('service:store');
- let person, people;
+ let person, people;
- run(() => {
- store.push({
- data: {
- type: 'person',
- id: '1',
- },
+ run(() => {
+ store.push({
+ data: {
+ type: 'person',
+ id: '1',
+ },
+ });
+ person = store.peekRecord('person', 1);
+ people = store.peekAll('person');
+ person.deleteRecord();
});
- person = store.peekRecord('person', 1);
- people = store.peekAll('person');
- person.deleteRecord();
- });
- assert.equal(people.get('length'), 1, 'a deleted record appears in the record array until it is saved');
- assert.equal(people.objectAt(0), person, 'a deleted record appears in the record array until it is saved');
+ assert.equal(people.get('length'), 1, 'a deleted record appears in the record array until it is saved');
+ assert.equal(people.objectAt(0), person, 'a deleted record appears in the record array until it is saved');
- assert.equal(person.get('isDeleted'), true, 'must be deleted');
+ assert.equal(person.get('isDeleted'), true, 'must be deleted');
- run(() => person.rollbackAttributes());
+ run(() => person.rollbackAttributes());
- assert.equal(people.get('length'), 1, 'the rollbacked record should appear again in the record array');
- assert.equal(person.get('isDeleted'), false, 'must not be deleted');
- assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty');
- });
-
- test("invalid record's attributes can be rollbacked", async function(assert) {
- assert.expect(13);
+ assert.equal(people.get('length'), 1, 'the rollbacked record should appear again in the record array');
+ assert.equal(person.get('isDeleted'), false, 'must not be deleted');
+ assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty');
+ });
- class Dog extends Model {
- @attr() name;
- rolledBackCount = 0;
- rolledBack() {
- this.incrementProperty('rolledBackCount');
+ test("invalid record's attributes can be rollbacked", async function(assert) {
+ class Dog extends Model {
+ @attr() name;
+ rolledBackCount = 0;
+ rolledBack() {
+ this.incrementProperty('rolledBackCount');
+ }
}
- }
- const thrownAdapterError = new InvalidError([
- {
- detail: 'is invalid',
- source: { pointer: 'data/attributes/name' },
- },
- ]);
- class TestAdapter extends RESTAdapter {
- ajax() {
- return reject(thrownAdapterError);
+ const thrownAdapterError = new InvalidError([
+ {
+ detail: 'is invalid',
+ source: { pointer: 'data/attributes/name' },
+ },
+ ]);
+ class TestAdapter extends RESTAdapter {
+ ajax() {
+ return reject(thrownAdapterError);
+ }
}
- }
- const { owner } = this;
- owner.register(`model:dog`, Dog);
- owner.register(`adapter:application`, TestAdapter);
- owner.register(`serializer:application`, RESTSerializer.extend());
- const store = owner.lookup(`service:store`);
+ const { owner } = this;
+ owner.register(`model:dog`, Dog);
+ owner.register(`adapter:application`, TestAdapter);
+ owner.register(`serializer:application`, RESTSerializer.extend());
+ const store = owner.lookup(`service:store`);
- const dog = store.push({
- data: {
- type: 'dog',
- id: '1',
- attributes: {
- name: 'Pluto',
+ const dog = store.push({
+ data: {
+ type: 'dog',
+ id: '1',
+ attributes: {
+ name: 'Pluto',
+ },
},
- },
- });
- dog.set('name', 'is a dwarf planet');
+ });
+ dog.set('name', 'is a dwarf planet');
- addObserver(dog, 'errors.name', function() {
- assert.ok(true, 'errors.name did change');
- });
+ addObserver(dog, 'errors.name', function() {
+ assert.ok(true, 'errors.name did change');
+ });
- dog.get('errors').addArrayObserver(
- {},
- {
- willChange() {
- assert.ok(true, 'errors will change');
- },
- didChange() {
- assert.ok(true, 'errors did change');
- },
- }
- );
+ dog.get('errors').addArrayObserver(
+ {},
+ {
+ willChange() {
+ assert.ok(true, 'errors will change');
+ },
+ didChange() {
+ assert.ok(true, 'errors did change');
+ },
+ }
+ );
- try {
- assert.ok(true, 'saving');
- await dog.save();
- } catch (reason) {
- assert.equal(reason, thrownAdapterError, 'We threw the expected error during save');
+ try {
+ assert.ok(true, 'saving');
+ await dog.save();
+ } catch (reason) {
+ assert.equal(reason, thrownAdapterError, 'We threw the expected error during save');
- dog.rollbackAttributes();
- await settled();
+ dog.rollbackAttributes();
+ await settled();
- assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty');
- assert.equal(dog.get('name'), 'Pluto', 'Name is rolled back');
- assert.notOk(dog.get('errors.name'), 'We have no errors for name anymore');
- assert.ok(dog.get('isValid'), 'We are now in a valid state');
- assert.equal(dog.get('rolledBackCount'), 1, 'we only rolled back once');
- }
+ assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty');
+ assert.equal(dog.get('name'), 'Pluto', 'Name is rolled back');
+ assert.notOk(dog.get('errors.name'), 'We have no errors for name anymore');
+ assert.ok(dog.get('isValid'), 'We are now in a valid state');
+ assert.equal(dog.get('rolledBackCount'), 1, 'we only rolled back once');
+ }
+ });
});
test(`invalid record's attributes rolled back to correct state after set`, async function(assert) {
- assert.expect(14);
-
class Dog extends Model {
@attr() name;
@attr() breed;
diff --git a/packages/-ember-data/tests/unit/record-arrays/adapter-populated-record-array-test.js b/packages/-ember-data/tests/unit/record-arrays/adapter-populated-record-array-test.js
index 90493ff4c9f..7f1afeafdb2 100644
--- a/packages/-ember-data/tests/unit/record-arrays/adapter-populated-record-array-test.js
+++ b/packages/-ember-data/tests/unit/record-arrays/adapter-populated-record-array-test.js
@@ -155,10 +155,13 @@ module('unit/record-arrays/adapter-populated-record-array - DS.AdapterPopulatedR
assert.equal(recordArray.get('meta').bar, 2);
});
assert.equal(didLoad, 1, 'didLoad event should have fired once');
+ assert.expectDeprecation({
+ id: 'ember-data:evented-api-usage',
+ });
});
test('change events when receiving a new query payload', function(assert) {
- assert.expect(37);
+ assert.expect(38);
let arrayDidChange = 0;
let contentDidChange = 0;
@@ -276,5 +279,9 @@ module('unit/record-arrays/adapter-populated-record-array - DS.AdapterPopulatedR
assert.equal(contentDidChange, 0, 'recordArray.content should not have changed');
assert.deepEqual(recordArray.map(x => x.name), ['Scumbag Penner']);
+ assert.expectDeprecation({
+ id: 'ember-data:evented-api-usage',
+ count: 1,
+ });
});
});
diff --git a/packages/-ember-data/tests/unit/store/adapter-interop-test.js b/packages/-ember-data/tests/unit/store/adapter-interop-test.js
index 39e162990f8..c64d8d86ee2 100644
--- a/packages/-ember-data/tests/unit/store/adapter-interop-test.js
+++ b/packages/-ember-data/tests/unit/store/adapter-interop-test.js
@@ -13,32 +13,47 @@ import JSONSerializer from '@ember-data/serializer/json';
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
import RESTAdapter from '@ember-data/adapter/rest';
import Store from '@ember-data/store';
+import { deprecatedTest } from '../../helpers/deprecated-test';
module('unit/store/adapter-interop - Store working with a Adapter', function(hooks) {
setupTest(hooks);
- test('Adapter can be set as a name', function(assert) {
- this.owner.register('service:store', Store.extend({ adapter: 'application' }));
+ deprecatedTest(
+ 'Adapter can be set as a name',
+ {
+ id: 'ember-data:default-adapter',
+ until: '4.0',
+ },
+ function(assert) {
+ this.owner.register('service:store', Store.extend({ adapter: 'application' }));
- let store = this.owner.lookup('service:store');
+ let store = this.owner.lookup('service:store');
- assert.ok(store.get('defaultAdapter') instanceof RESTAdapter);
- });
+ assert.ok(store.get('defaultAdapter') instanceof RESTAdapter);
+ }
+ );
- testInDebug('Adapter can not be set as an instance', function(assert) {
- assert.expect(1);
+ deprecatedTest(
+ 'Adapter can not be set as an instance',
+ {
+ id: 'ember-data:default-adapter',
+ until: '4.0',
+ },
+ function(assert) {
+ assert.expect(1);
- const BadStore = Store.extend({
- adapter: Adapter.create(),
- });
+ const BadStore = Store.extend({
+ adapter: Adapter.create(),
+ });
- const { owner } = this;
+ const { owner } = this;
- owner.unregister('service:store');
- owner.register('service:store', BadStore);
- const store = owner.lookup('service:store');
- assert.expectAssertion(() => store.get('defaultAdapter'));
- });
+ owner.unregister('service:store');
+ owner.register('service:store', BadStore);
+ const store = owner.lookup('service:store');
+ assert.expectAssertion(() => store.get('defaultAdapter'));
+ }
+ );
test('Calling Store#find invokes its adapter#find', function(assert) {
assert.expect(5);
diff --git a/packages/-ember-data/tests/unit/store/push-test.js b/packages/-ember-data/tests/unit/store/push-test.js
index b5b2736ac31..6dec599199f 100644
--- a/packages/-ember-data/tests/unit/store/push-test.js
+++ b/packages/-ember-data/tests/unit/store/push-test.js
@@ -147,8 +147,8 @@ module('unit/store/push - DS.Store#push', function(hooks) {
});
});
- test(`Calling push triggers 'didLoad' even if the record hasn't been requested from the adapter`, function(assert) {
- assert.expect(1);
+ test(`Calling push triggers 'didLoad' even if the record hasn't been requested from the adapter`, async function(assert) {
+ assert.expect(2);
let didLoad = new EmberPromise((resolve, reject) => {
Person.reopen({
@@ -176,7 +176,10 @@ module('unit/store/push - DS.Store#push', function(hooks) {
});
});
- return didLoad;
+ await didLoad;
+ assert.expectDeprecation({
+ id: 'ember-data:record-lifecycle-event-methods',
+ });
});
test('Calling push with partial records updates just those attributes', function(assert) {
diff --git a/packages/-ember-data/tests/unit/store/serializer-for-test.js b/packages/-ember-data/tests/unit/store/serializer-for-test.js
index 6847551a163..4c6917415d5 100644
--- a/packages/-ember-data/tests/unit/store/serializer-for-test.js
+++ b/packages/-ember-data/tests/unit/store/serializer-for-test.js
@@ -43,7 +43,7 @@ module('unit/store/serializer_for - DS.Store#serializerFor', function(hooks) {
deprecatedTest(
'Calling serializerFor with a type that has not been registered and in an application that does not have an ApplicationSerializer looks up the default Ember Data serializer',
{
- id: 'ember-data:default-serializers',
+ id: 'ember-data:default-serializer',
until: '4.0',
},
function(assert) {
diff --git a/packages/adapter/addon/rest.js b/packages/adapter/addon/rest.js
index 4e67d528354..f4428faf141 100644
--- a/packages/adapter/addon/rest.js
+++ b/packages/adapter/addon/rest.js
@@ -1086,7 +1086,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, {
let headers = get(this, 'headers');
if (headers !== undefined) {
- options.headers = assign({}, options.headers, headers);
+ options.headers = assign({}, headers, options.headers);
} else if (!options.headers) {
options.headers = {};
}
diff --git a/packages/store/addon/-private/system/model/errors.js b/packages/model/addon/-private/errors.js
similarity index 98%
rename from packages/store/addon/-private/system/model/errors.js
rename to packages/model/addon/-private/errors.js
index 4fa216bdc62..1e11a3a757d 100644
--- a/packages/store/addon/-private/system/model/errors.js
+++ b/packages/model/addon/-private/errors.js
@@ -1,5 +1,5 @@
import { mapBy, not } from '@ember/object/computed';
-import DeprecatedEvent from '../deprecated-evented';
+import { DeprecatedEvented } from '@ember-data/store/-private';
import ArrayProxy from '@ember/array/proxy';
import { get, computed } from '@ember/object';
import { makeArray, A } from '@ember/array';
@@ -82,7 +82,7 @@ import { DEBUG } from '@glimmer/env';
@extends Ember.ArrayProxy
@uses Ember.Evented
*/
-export default ArrayProxy.extend(DeprecatedEvent, {
+export default ArrayProxy.extend(DeprecatedEvented, {
/**
Register with target handler
diff --git a/packages/model/addon/-private/index.ts b/packages/model/addon/-private/index.ts
index 161b31d72d5..b4a458de87d 100644
--- a/packages/model/addon/-private/index.ts
+++ b/packages/model/addon/-private/index.ts
@@ -2,3 +2,4 @@ export { default as attr } from './attr';
export { default as belongsTo } from './belongs-to';
export { default as hasMany } from './has-many';
export { default as Model } from './model';
+export { default as Errors } from './errors';
diff --git a/packages/model/addon/-private/model.js b/packages/model/addon/-private/model.js
index 4b18dffc8da..8f98ebc26fa 100644
--- a/packages/model/addon/-private/model.js
+++ b/packages/model/addon/-private/model.js
@@ -9,7 +9,6 @@ import {
coerceId,
DeprecatedEvented,
errorsArrayToHash,
- Errors,
InternalModel,
PromiseObject,
recordDataFor,
@@ -20,6 +19,7 @@ import {
relationshipsDescriptor,
RootState,
} from '@ember-data/store/-private';
+import Errors from './errors';
const { changeProperties } = Ember;
diff --git a/packages/record-data/addon/-private/relationships/state/belongs-to.ts b/packages/record-data/addon/-private/relationships/state/belongs-to.ts
index f449a3d8473..b0d6e5bc489 100644
--- a/packages/record-data/addon/-private/relationships/state/belongs-to.ts
+++ b/packages/record-data/addon/-private/relationships/state/belongs-to.ts
@@ -95,7 +95,6 @@ export default class BelongsToRelationship extends Relationship {
this.notifyBelongsToChange();
}
}
-
removeCompletelyFromInverse() {
super.removeCompletelyFromInverse();
diff --git a/packages/store/addon/-private/index.ts b/packages/store/addon/-private/index.ts
index fa9d2d42b25..91243f2f036 100644
--- a/packages/store/addon/-private/index.ts
+++ b/packages/store/addon/-private/index.ts
@@ -2,8 +2,6 @@
@module @ember-data/store
*/
-// // public
-export { default as Errors } from './system/model/errors';
export { default as Store } from './system/ds-model-store';
export { recordIdentifierFor } from './system/store/internal-model-factory';
diff --git a/packages/store/addon/-private/system/core-store.ts b/packages/store/addon/-private/system/core-store.ts
index 590db4d4cbe..b4cf1b8b3e2 100644
--- a/packages/store/addon/-private/system/core-store.ts
+++ b/packages/store/addon/-private/system/core-store.ts
@@ -68,7 +68,7 @@ import { DSModel } from '../ts-interfaces/ds-model';
import NotificationManager from './record-notification-manager';
import { AttributesSchema } from '../ts-interfaces/record-data-schemas';
import { SchemaDefinitionService } from '../ts-interfaces/schema-definition-service';
-import ShimModelClass from './model/shim-model-class';
+import ShimModelClass, { getShimClass } from './model/shim-model-class';
import RecordDataRecordWrapper from '../ts-interfaces/record-data-record-wrapper';
import RecordData from '../ts-interfaces/record-data';
import { Dict } from '../ts-interfaces/utils';
@@ -513,7 +513,7 @@ abstract class CoreStore extends Service {
assertDestroyedStoreOnly(this, 'modelFor');
}
- return new ShimModelClass(this, modelName);
+ return getShimClass(this, modelName);
}
// Feature Flagged in DSModelStore
diff --git a/packages/store/addon/-private/system/ds-model-store.ts b/packages/store/addon/-private/system/ds-model-store.ts
index 59b35d9b3c8..a79406e3213 100644
--- a/packages/store/addon/-private/system/ds-model-store.ts
+++ b/packages/store/addon/-private/system/ds-model-store.ts
@@ -10,7 +10,7 @@ import { isPresent } from '@ember/utils';
import { deprecate } from '@ember/application/deprecations';
import EmberError from '@ember/error';
import { get } from '@ember/object';
-import ShimModelClass from './model/shim-model-class';
+import ShimModelClass, { getShimClass } from './model/shim-model-class';
import { setOwner, getOwner } from '@ember/application';
import { DSModel } from '../ts-interfaces/ds-model';
import NotificationManager from './record-notification-manager';
@@ -21,6 +21,7 @@ import RecordDataRecordWrapper from '../ts-interfaces/record-data-record-wrapper
import { SchemaDefinitionService } from '../ts-interfaces/schema-definition-service';
import { RelationshipsSchema } from '../ts-interfaces/record-data-schemas';
import notifyChanges from './model/notify-changes';
+type DSModelClass = import('@ember-data/model').default;
/**
The store service contains all of the data for records loaded from the server.
@@ -143,7 +144,7 @@ class Store extends CoreStore {
@param {String} modelName
@return {Model}
*/
- modelFor(modelName) {
+ modelFor(modelName: string): ShimModelClass | DSModelClass {
if (DEBUG) {
assertDestroyedStoreOnly(this, 'modelFor');
}
@@ -156,15 +157,18 @@ class Store extends CoreStore {
let maybeFactory = this._modelFactoryFor(modelName);
// for factorFor factory/class split
- let klass = maybeFactory.class ? maybeFactory.class : maybeFactory;
- if (!klass.isModel) {
- return new ShimModelClass(this, modelName);
+ let klass = maybeFactory && maybeFactory.class ? maybeFactory.class : maybeFactory;
+ if (!klass || !klass.isModel) {
+ if (!CUSTOM_MODEL_CLASS || !this.getSchemaDefinitionService().doesTypeExist(modelName)) {
+ throw new EmberError(`No model was found for '${modelName}' and no schema handles the type`);
+ }
+ return getShimClass(this, modelName);
} else {
return klass;
}
}
- _modelFactoryFor(modelName) {
+ _modelFactoryFor(modelName: string): DSModelClass {
if (DEBUG) {
assertDestroyedStoreOnly(this, '_modelFactoryFor');
}
@@ -176,10 +180,6 @@ class Store extends CoreStore {
let normalizedModelName = normalizeModelName(modelName);
let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName);
- if (factory === null) {
- throw new EmberError(`No model was found for '${normalizedModelName}'`);
- }
-
return factory;
}
diff --git a/packages/store/addon/-private/system/model/internal-model.ts b/packages/store/addon/-private/system/model/internal-model.ts
index b26350fcbb0..cf63ac6a80c 100644
--- a/packages/store/addon/-private/system/model/internal-model.ts
+++ b/packages/store/addon/-private/system/model/internal-model.ts
@@ -758,7 +758,7 @@ export default class InternalModel {
loadingPromise = this.store
._findHasManyByJsonApiResource(jsonApi, this, relationshipMeta, options)
- .then(initialState => {
+ .then(() => {
// TODO why don't we do this in the store method
manyArray.retrieveLatest();
manyArray.set('isLoaded', true);
diff --git a/packages/store/addon/-private/system/model/shim-model-class.ts b/packages/store/addon/-private/system/model/shim-model-class.ts
index 33147f9cc52..83ad278011e 100644
--- a/packages/store/addon/-private/system/model/shim-model-class.ts
+++ b/packages/store/addon/-private/system/model/shim-model-class.ts
@@ -1,5 +1,24 @@
import CoreStore from '../core-store';
import { RelationshipSchema, AttributeSchema } from '../../ts-interfaces/record-data-schemas';
+import { Dict } from '../../ts-interfaces/utils';
+
+const AvailableShims = new WeakMap>();
+
+export function getShimClass(store: CoreStore, modelName: string): ShimModelClass {
+ let shims = AvailableShims.get(store);
+
+ if (shims === undefined) {
+ shims = Object.create(null) as Dict;
+ AvailableShims.set(store, shims);
+ }
+
+ let shim = shims[modelName];
+ if (shim === undefined) {
+ shim = shims[modelName] = new ShimModelClass(store, modelName);
+ }
+
+ return shim;
+}
// Mimics the static apis of DSModel
export default class ShimModelClass {
diff --git a/packages/store/addon/-private/system/schema-definition-service.ts b/packages/store/addon/-private/system/schema-definition-service.ts
index f1a8a92d5a8..a7ec125e67b 100644
--- a/packages/store/addon/-private/system/schema-definition-service.ts
+++ b/packages/store/addon/-private/system/schema-definition-service.ts
@@ -5,6 +5,8 @@ import { getOwner } from '@ember/application';
import normalizeModelName from './normalize-model-name';
import { RelationshipsSchema, AttributesSchema } from '../ts-interfaces/record-data-schemas';
import require, { has } from 'require';
+import CoreStore from './core-store';
+type Model = import('@ember-data/model').default;
const HAS_MODEL_PACKAGE = has('@ember-data/model');
let _Model;
@@ -80,7 +82,7 @@ export class DSModelSchemaDefinitionService {
* @param normalizedModelName already normalized modelName
* @return {*}
*/
-export function getModelFactory(store, cache, normalizedModelName) {
+export function getModelFactory(store: CoreStore, cache, normalizedModelName: string): Model | null {
let factory = cache[normalizedModelName];
if (!factory) {
@@ -97,9 +99,7 @@ export function getModelFactory(store, cache, normalizedModelName) {
}
let klass = factory.class;
- // assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel);
- // TODO: deprecate this
if (klass.isModel) {
let hasOwnModelNameSet = klass.modelName && Object.prototype.hasOwnProperty.call(klass, 'modelName');
if (!hasOwnModelNameSet) {
diff --git a/packages/-fastboot-test-app/app/routes/person/new.js b/packages/unpublished-fastboot-test-app/app/routes/person/new.js
similarity index 100%
rename from packages/-fastboot-test-app/app/routes/person/new.js
rename to packages/unpublished-fastboot-test-app/app/routes/person/new.js
diff --git a/packages/-fastboot-test-app/app/templates/person/new.hbs b/packages/unpublished-fastboot-test-app/app/templates/person/new.hbs
similarity index 100%
rename from packages/-fastboot-test-app/app/templates/person/new.hbs
rename to packages/unpublished-fastboot-test-app/app/templates/person/new.hbs
diff --git a/packages/-fastboot-test-app/tests/fastboot/person/new-test.js b/packages/unpublished-fastboot-test-app/tests/fastboot/person/new-test.js
similarity index 100%
rename from packages/-fastboot-test-app/tests/fastboot/person/new-test.js
rename to packages/unpublished-fastboot-test-app/tests/fastboot/person/new-test.js
diff --git a/packages/unpublished-model-encapsulation-test-app/app/app.js b/packages/unpublished-model-encapsulation-test-app/app/app.js
index f08aaaf0304..bfd9f02e6ae 100644
--- a/packages/unpublished-model-encapsulation-test-app/app/app.js
+++ b/packages/unpublished-model-encapsulation-test-app/app/app.js
@@ -3,6 +3,13 @@ import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
+window.EmberDataENV = {
+ ENABLE_OPTIONAL_FEATURES: true,
+ FEATURES: {
+ CUSTOM_MODEL_CLASS: true,
+ },
+};
+
const App = Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
diff --git a/packages/unpublished-model-encapsulation-test-app/tests/integration/model-for-test.js b/packages/unpublished-model-encapsulation-test-app/tests/integration/model-for-test.js
new file mode 100644
index 00000000000..e65abd23e79
--- /dev/null
+++ b/packages/unpublished-model-encapsulation-test-app/tests/integration/model-for-test.js
@@ -0,0 +1,97 @@
+import Store from '@ember-data/store';
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('modelFor without @ember-data/model', function(hooks) {
+ setupTest(hooks);
+
+ test('We can call modelFor', function(assert) {
+ this.owner.register(
+ 'service:store',
+ class TestStore extends Store {
+ instantiateRecord() {
+ return {
+ id: '1',
+ type: 'user',
+ name: 'Chris Thoburn',
+ };
+ }
+ teardownRecord() {
+ return;
+ }
+ }
+ );
+ const store = this.owner.lookup('service:store');
+ store.registerSchemaDefinitionService({
+ attributesDefinitionFor(identifier) {
+ return {
+ name: {
+ name: 'name',
+ },
+ };
+ },
+ relationshipsDefinitionFor(identifier) {
+ return {};
+ },
+ doesTypeExist(type) {
+ return type === 'user';
+ },
+ });
+
+ try {
+ store.modelFor('user');
+ assert.ok(true, 'We should not throw an eror when schema is available');
+ } catch (e) {
+ assert.ok(false, `We threw an unexpected error when schema is available: ${e.message}`);
+ }
+
+ try {
+ store.modelFor('person');
+ assert.ok(false, 'We should throw an eror when no schema is available');
+ } catch (e) {
+ assert.strictEqual(
+ e.message,
+ "No model was found for 'person' and no schema handles the type",
+ 'We throw an error when no schema is available'
+ );
+ }
+ });
+
+ test('modelFor returns a stable reference', function(assert) {
+ this.owner.register(
+ 'service:store',
+ class TestStore extends Store {
+ instantiateRecord() {
+ return {
+ id: '1',
+ type: 'user',
+ name: 'Chris Thoburn',
+ };
+ }
+ teardownRecord() {
+ return;
+ }
+ }
+ );
+ const store = this.owner.lookup('service:store');
+ store.registerSchemaDefinitionService({
+ attributesDefinitionFor(identifier) {
+ return {
+ name: {
+ name: 'name',
+ },
+ };
+ },
+ relationshipsDefinitionFor(identifier) {
+ return {};
+ },
+ doesTypeExist(type) {
+ return type === 'user';
+ },
+ });
+
+ const ShimUser1 = store.modelFor('user');
+ const ShimUser2 = store.modelFor('user');
+ assert.strictEqual(ShimUser1, ShimUser2, 'Repeat modelFor calls return the same shim');
+ });
+});
diff --git a/packages/unpublished-relationship-performance-test-app/PERFORMANCE_BENCHMARKING.md b/packages/unpublished-relationship-performance-test-app/PERFORMANCE_BENCHMARKING.md
index 370cae484cb..2b3849a964a 100644
--- a/packages/unpublished-relationship-performance-test-app/PERFORMANCE_BENCHMARKING.md
+++ b/packages/unpublished-relationship-performance-test-app/PERFORMANCE_BENCHMARKING.md
@@ -9,5 +9,5 @@ A HAR file has already been created for this app from a production build. It can
Next, run the following from the root of this repository:
```
-./bin/relationship-performance-check
+./bin/relationship-performance-tracking/src/generate-analysis.sh
```
diff --git a/packages/unpublished-relationship-performance-test-app/tracerbench-results/.gitignore b/packages/unpublished-relationship-performance-test-app/tracerbench-results/.gitignore
index 94a2dd146a2..f59ec20aabf 100644
--- a/packages/unpublished-relationship-performance-test-app/tracerbench-results/.gitignore
+++ b/packages/unpublished-relationship-performance-test-app/tracerbench-results/.gitignore
@@ -1 +1 @@
-*.json
\ No newline at end of file
+*
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index f538c45824c..24558dd3d82 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -39,6 +39,16 @@
lodash "^4.17.13"
source-map "^0.5.0"
+"@babel/generator@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.7.0.tgz#c6d4d1f7a0d6e139cbd01aca73170b0bff5425b4"
+ integrity sha512-1wdJ6UxHyL1XoJQ119JmvuRX27LRih7iYStMPZOWAjQqeAabFg3dYXKMpgihma+to+0ADsTVVt6oRyUxWZw6Mw==
+ dependencies:
+ "@babel/types" "^7.7.0"
+ jsesc "^2.5.1"
+ lodash "^4.17.13"
+ source-map "^0.5.0"
+
"@babel/helper-annotate-as-pure@^7.0.0":
version "7.0.0"
resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32"
@@ -63,17 +73,17 @@
"@babel/traverse" "^7.4.4"
"@babel/types" "^7.4.4"
-"@babel/helper-create-class-features-plugin@^7.5.5", "@babel/helper-create-class-features-plugin@^7.6.0":
- version "7.6.0"
- resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.6.0.tgz#769711acca889be371e9bc2eb68641d55218021f"
- integrity sha512-O1QWBko4fzGju6VoVvrZg0RROCVifcLxiApnGP3OWfWzvxRZFCoBD81K5ur5e3bVY2Vf/5rIJm8cqPKn8HUJng==
+"@babel/helper-create-class-features-plugin@^7.5.5", "@babel/helper-create-class-features-plugin@^7.6.0", "@babel/helper-create-class-features-plugin@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.0.tgz#bcdc223abbfdd386f94196ae2544987f8df775e8"
+ integrity sha512-MZiB5qvTWoyiFOgootmRSDV1udjIqJW/8lmxgzKq6oDqxdmHUjeP2ZUOmgHdYjmUVNABqRrHjYAYRvj8Eox/UA==
dependencies:
- "@babel/helper-function-name" "^7.1.0"
- "@babel/helper-member-expression-to-functions" "^7.5.5"
- "@babel/helper-optimise-call-expression" "^7.0.0"
+ "@babel/helper-function-name" "^7.7.0"
+ "@babel/helper-member-expression-to-functions" "^7.7.0"
+ "@babel/helper-optimise-call-expression" "^7.7.0"
"@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-replace-supers" "^7.5.5"
- "@babel/helper-split-export-declaration" "^7.4.4"
+ "@babel/helper-replace-supers" "^7.7.0"
+ "@babel/helper-split-export-declaration" "^7.7.0"
"@babel/helper-define-map@^7.5.5":
version "7.5.5"
@@ -101,6 +111,15 @@
"@babel/template" "^7.1.0"
"@babel/types" "^7.0.0"
+"@babel/helper-function-name@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.0.tgz#44a5ad151cfff8ed2599c91682dda2ec2c8430a3"
+ integrity sha512-tDsJgMUAP00Ugv8O2aGEua5I2apkaQO7lBGUq1ocwN3G23JE5Dcq0uh3GvFTChPa4b40AWiAsLvCZOA2rdnQ7Q==
+ dependencies:
+ "@babel/helper-get-function-arity" "^7.7.0"
+ "@babel/template" "^7.7.0"
+ "@babel/types" "^7.7.0"
+
"@babel/helper-get-function-arity@^7.0.0":
version "7.0.0"
resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3"
@@ -108,6 +127,13 @@
dependencies:
"@babel/types" "^7.0.0"
+"@babel/helper-get-function-arity@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.0.tgz#c604886bc97287a1d1398092bc666bc3d7d7aa2d"
+ integrity sha512-tLdojOTz4vWcEnHWHCuPN5P85JLZWbm5Fx5ZsMEMPhF3Uoe3O7awrbM2nQ04bDOUToH/2tH/ezKEOR8zEYzqyw==
+ dependencies:
+ "@babel/types" "^7.7.0"
+
"@babel/helper-hoist-variables@^7.4.4":
version "7.4.4"
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a"
@@ -122,6 +148,13 @@
dependencies:
"@babel/types" "^7.5.5"
+"@babel/helper-member-expression-to-functions@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.0.tgz#472b93003a57071f95a541ea6c2b098398bcad8a"
+ integrity sha512-QaCZLO2RtBcmvO/ekOLp8p7R5X2JriKRizeDpm5ChATAFWrrYDcDxPuCIBXKyBjY+i1vYSdcUTMIb8psfxHDPA==
+ dependencies:
+ "@babel/types" "^7.7.0"
+
"@babel/helper-module-imports@^7.0.0":
version "7.0.0"
resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
@@ -148,6 +181,13 @@
dependencies:
"@babel/types" "^7.0.0"
+"@babel/helper-optimise-call-expression@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.0.tgz#4f66a216116a66164135dc618c5d8b7a959f9365"
+ integrity sha512-48TeqmbazjNU/65niiiJIJRc5JozB8acui1OS7bSd6PgxfuovWsvjfWSzlgx+gPFdVveNzUdpdIg5l56Pl5jqg==
+ dependencies:
+ "@babel/types" "^7.7.0"
+
"@babel/helper-plugin-utils@^7.0.0":
version "7.0.0"
resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250"
@@ -181,6 +221,16 @@
"@babel/traverse" "^7.5.5"
"@babel/types" "^7.5.5"
+"@babel/helper-replace-supers@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.0.tgz#d5365c8667fe7cbd13b8ddddceb9bd7f2b387512"
+ integrity sha512-5ALYEul5V8xNdxEeWvRsBzLMxQksT7MaStpxjJf9KsnLxpAKBtfw5NeMKZJSYDa0lKdOcy0g+JT/f5mPSulUgg==
+ dependencies:
+ "@babel/helper-member-expression-to-functions" "^7.7.0"
+ "@babel/helper-optimise-call-expression" "^7.7.0"
+ "@babel/traverse" "^7.7.0"
+ "@babel/types" "^7.7.0"
+
"@babel/helper-simple-access@^7.1.0":
version "7.1.0"
resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c"
@@ -196,6 +246,13 @@
dependencies:
"@babel/types" "^7.4.4"
+"@babel/helper-split-export-declaration@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.0.tgz#1365e74ea6c614deeb56ebffabd71006a0eb2300"
+ integrity sha512-HgYSI8rH08neWlAH3CcdkFg9qX9YsZysZI5GD8LjhQib/mM0jGOZOVkoUiiV2Hu978fRtjtsGsW6w0pKHUWtqA==
+ dependencies:
+ "@babel/types" "^7.7.0"
+
"@babel/helper-wrap-function@^7.1.0":
version "7.2.0"
resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa"
@@ -229,6 +286,11 @@
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81"
integrity sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==
+"@babel/parser@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.7.0.tgz#232618f6e8947bc54b407fa1f1c91a22758e7159"
+ integrity sha512-GqL+Z0d7B7ADlQBMXlJgvXEbtt5qlqd1YQ5fr12hTSfh7O/vgrEIvJxU2e7aSVrEUn75zTZ6Nd0s8tthrlZnrQ==
+
"@babel/plugin-proposal-async-generator-functions@^7.2.0":
version "7.2.0"
resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e"
@@ -599,12 +661,12 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-typescript@^7.6.3":
- version "7.6.3"
- resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.6.3.tgz#dddb50cf3b8b2ef70b22e5326e9a91f05a1db13b"
- integrity sha512-aiWINBrPMSC3xTXRNM/dfmyYuPNKY/aexYqBgh0HBI5Y+WO5oRAqW/oROYeYHrF4Zw12r9rK4fMk/ZlAmqx/FQ==
+"@babel/plugin-transform-typescript@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.7.0.tgz#182be03fa8bd2ffd0629791a1eaa4373b7589d38"
+ integrity sha512-y3KYbcfKe+8ziRXiGhhnGrVysDBo5+aJdB+x8sanM0K41cnmK7Q5vBlQLMbOnW/HPjLG9bg7dLgYDQZZG9T09g==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.6.0"
+ "@babel/helper-create-class-features-plugin" "^7.7.0"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-typescript" "^7.2.0"
@@ -714,6 +776,15 @@
"@babel/parser" "^7.6.0"
"@babel/types" "^7.6.0"
+"@babel/template@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/template/-/template-7.7.0.tgz#4fadc1b8e734d97f56de39c77de76f2562e597d0"
+ integrity sha512-OKcwSYOW1mhWbnTBgQY5lvg1Fxg+VyfQGjcBduZFljfc044J5iDlnDSfhQ867O17XHiSCxYHUxHg2b7ryitbUQ==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ "@babel/parser" "^7.7.0"
+ "@babel/types" "^7.7.0"
+
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.2.4", "@babel/traverse@^7.3.4", "@babel/traverse@^7.4.4", "@babel/traverse@^7.4.5", "@babel/traverse@^7.5.5", "@babel/traverse@^7.6.2", "@babel/traverse@^7.6.3":
version "7.6.3"
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz#66d7dba146b086703c0fb10dd588b7364cec47f9"
@@ -729,6 +800,21 @@
globals "^11.1.0"
lodash "^4.17.13"
+"@babel/traverse@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.0.tgz#9f5744346b8d10097fd2ec2eeffcaf19813cbfaf"
+ integrity sha512-ea/3wRZc//e/uwCpuBX2itrhI0U9l7+FsrKWyKGNyvWbuMcCG7ATKY2VI4wlg2b2TA39HHwIxnvmXvtiKsyn7w==
+ dependencies:
+ "@babel/code-frame" "^7.5.5"
+ "@babel/generator" "^7.7.0"
+ "@babel/helper-function-name" "^7.7.0"
+ "@babel/helper-split-export-declaration" "^7.7.0"
+ "@babel/parser" "^7.7.0"
+ "@babel/types" "^7.7.0"
+ debug "^4.1.0"
+ globals "^11.1.0"
+ lodash "^4.17.13"
+
"@babel/types@^7.0.0", "@babel/types@^7.1.6", "@babel/types@^7.2.0", "@babel/types@^7.3.2", "@babel/types@^7.3.4", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0", "@babel/types@^7.6.3":
version "7.6.3"
resolved "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz#3f07d96f854f98e2fbd45c64b0cb942d11e8ba09"
@@ -738,6 +824,15 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
+"@babel/types@^7.7.0":
+ version "7.7.1"
+ resolved "https://registry.npmjs.org/@babel/types/-/types-7.7.1.tgz#8b08ea368f2baff236613512cf67109e76285827"
+ integrity sha512-kN/XdANDab9x1z5gcjDc9ePpxexkt+1EQ2MQUiM4XnMvQfvp87/+6kY4Ko2maLXH+tei/DgJ/ybFITeqqRwDiA==
+ dependencies:
+ esutils "^2.0.2"
+ lodash "^4.17.13"
+ to-fast-properties "^2.0.0"
+
"@cnakazawa/watch@^1.0.3":
version "1.0.3"
resolved "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
@@ -2087,46 +2182,47 @@
resolved "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d"
integrity sha1-EHPEvIJHVK49EM+riKsCN7qWTk0=
-"@typescript-eslint/eslint-plugin@^2.6.0":
- version "2.6.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.6.0.tgz#e82ed43fc4527b21bfe35c20a2d6e4ed49fc7957"
- integrity sha512-iCcXREU4RciLmLniwKLRPCOFVXrkF7z27XuHq5DrykpREv/mz6ztKAyLg2fdkM0hQC7659p5ZF5uStH7uzAJ/w==
+"@typescript-eslint/eslint-plugin@^2.6.1":
+ version "2.6.1"
+ resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.6.1.tgz#e34972a24f8aba0861f9ccf7130acd74fd11e079"
+ integrity sha512-Z0rddsGqioKbvqfohg7BwkFC3PuNLsB+GE9QkFza7tiDzuHoy0y823Y+oGNDzxNZrYyLjqkZtCTl4vCqOmEN4g==
dependencies:
- "@typescript-eslint/experimental-utils" "2.6.0"
+ "@typescript-eslint/experimental-utils" "2.6.1"
eslint-utils "^1.4.2"
functional-red-black-tree "^1.0.1"
regexpp "^2.0.1"
tsutils "^3.17.1"
-"@typescript-eslint/experimental-utils@2.6.0":
- version "2.6.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.6.0.tgz#ed70bef72822bff54031ff0615fc888b9e2b6e8a"
- integrity sha512-34BAFpNOwHXeqT+AvdalLxOvcPYnCxA5JGmBAFL64RGMdP0u65rXjii7l/nwpgk5aLEE1LaqF+SsCU0/Cb64xA==
+"@typescript-eslint/experimental-utils@2.6.1":
+ version "2.6.1"
+ resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.6.1.tgz#eddaca17a399ebf93a8628923233b4f93793acfd"
+ integrity sha512-EVrrUhl5yBt7fC7c62lWmriq4MIc49zpN3JmrKqfiFXPXCM5ErfEcZYfKOhZXkW6MBjFcJ5kGZqu1b+lyyExUw==
dependencies:
"@types/json-schema" "^7.0.3"
- "@typescript-eslint/typescript-estree" "2.6.0"
+ "@typescript-eslint/typescript-estree" "2.6.1"
eslint-scope "^5.0.0"
-"@typescript-eslint/parser@^2.6.0":
- version "2.6.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.6.0.tgz#5106295c6a7056287b4719e24aae8d6293d5af49"
- integrity sha512-AvLejMmkcjRTJ2KD72v565W4slSrrzUIzkReu1JN34b8JnsEsxx7S9Xx/qXEuMQas0mkdUfETr0j3zOhq2DIqQ==
+"@typescript-eslint/parser@^2.6.1":
+ version "2.6.1"
+ resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.6.1.tgz#3c00116baa0d696bc334ca18ac5286b34793993c"
+ integrity sha512-PDPkUkZ4c7yA+FWqigjwf3ngPUgoLaGjMlFh6TRtbjhqxFBnkElDfckSjm98q9cMr4xRzZ15VrS/xKm6QHYf0w==
dependencies:
"@types/eslint-visitor-keys" "^1.0.0"
- "@typescript-eslint/experimental-utils" "2.6.0"
- "@typescript-eslint/typescript-estree" "2.6.0"
+ "@typescript-eslint/experimental-utils" "2.6.1"
+ "@typescript-eslint/typescript-estree" "2.6.1"
eslint-visitor-keys "^1.1.0"
-"@typescript-eslint/typescript-estree@2.6.0":
- version "2.6.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.6.0.tgz#d3e9d8e001492e2b9124c4d4bd4e7f03c0fd7254"
- integrity sha512-A3lSBVIdj2Gp0lFEL6in2eSPqJ33uAc3Ko+Y4brhjkxzjbzLnwBH22CwsW2sCo+iwogfIyvb56/AJri15H0u5Q==
+"@typescript-eslint/typescript-estree@2.6.1":
+ version "2.6.1"
+ resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.6.1.tgz#fb363dd4ca23384745c5ea4b7f4c867432b00d31"
+ integrity sha512-+sTnssW6bcbDZKE8Ce7VV6LdzkQz2Bxk7jzk1J8H1rovoTxnm6iXvYIyncvNsaB/kBCOM63j/LNJfm27bNdUoA==
dependencies:
debug "^4.1.1"
glob "^7.1.4"
is-glob "^4.0.1"
lodash.unescape "4.0.1"
semver "^6.3.0"
+ tsutils "^3.17.1"
"@webassemblyjs/ast@1.7.11":
version "1.7.11"
@@ -2271,11 +2367,6 @@
"@webassemblyjs/wast-parser" "1.7.11"
"@xtuc/long" "4.2.1"
-"@xg-wang/whatwg-fetch@^3.0.0":
- version "3.0.0"
- resolved "https://registry.npmjs.org/@xg-wang/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#f7b222c012a238e7d6e89ed3d72a1e0edb58453d"
- integrity sha512-ULtqA6L75RLzTNW68IiOja0XYv4Ebc3OGMzfia1xxSEMpD0mk/pMvkQX0vbCFyQmKc5xGp80Ms2WiSlXLh8hbA==
-
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
@@ -6108,17 +6199,18 @@ ember-cli-preprocess-registry@^3.1.2, ember-cli-preprocess-registry@^3.3.0:
debug "^3.0.1"
process-relative-require "^1.0.0"
-ember-cli-pretender@^3.1.1:
- version "3.1.1"
- resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-3.1.1.tgz#289c41683de266fec8bfaf5b7b7f6026aaefc8cf"
- integrity sha512-RGGj9la0138bgHUxyaGDHCZydmdpW+BFN9v0vMBzNPeXsaexCZotaFTIZDCNcKWPx8jtRHR8AXf318VRGXLJsw==
+ember-cli-pretender@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-3.2.0.tgz#8d91a20bb5f57092a328317591ec1dd622fcadf1"
+ integrity sha512-3q7a0bjbHAevWaQQE447McT1neQIMgBjllfbOVX27D1qQqCZ5h6qMsRe7fU44B6/UQcCcghpbNoeEcNcI56wOg==
dependencies:
abortcontroller-polyfill "^1.1.9"
broccoli-funnel "^2.0.1"
broccoli-merge-trees "^3.0.0"
+ chalk "^2.4.2"
ember-cli-babel "^6.6.0"
fake-xml-http-request "^2.0.0"
- pretender "^2.1.0"
+ pretender "^3.0.1"
route-recognizer "^0.3.3"
whatwg-fetch "^3.0.0"
@@ -6263,10 +6355,10 @@ ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.0.1, ember-cli-ve
resolve-package-path "^1.2.6"
semver "^5.6.0"
-ember-cli-yuidoc@^0.8.8:
- version "0.8.8"
- resolved "https://registry.npmjs.org/ember-cli-yuidoc/-/ember-cli-yuidoc-0.8.8.tgz#3858baaf85388a976024f9de40f1075fea58f606"
- integrity sha1-OFi6r4U4ipdgJPneQPEHX+pY9gY=
+ember-cli-yuidoc@^0.9.1:
+ version "0.9.1"
+ resolved "https://registry.npmjs.org/ember-cli-yuidoc/-/ember-cli-yuidoc-0.9.1.tgz#bc2171eb160b02ad5f4078e83e3648b95628ced9"
+ integrity sha512-4pb3OKXhHCeUux6a7SDKziLDWdDciJwzmUld3Fumt60RLcH/nIk5lPdI0o+UXJ9NfP+WcSvvpWWroFmWqWAWWA==
dependencies:
broccoli-caching-writer "~2.0.4"
broccoli-merge-trees "^1.1.1"
@@ -11186,14 +11278,14 @@ prepend-http@^2.0.0:
resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
-pretender@^2.1.0:
- version "2.1.1"
- resolved "https://registry.npmjs.org/pretender/-/pretender-2.1.1.tgz#5085f0a1272c31d5b57c488386f69e6ca207cb35"
- integrity sha512-IkidsJzaroAanw3I43tKCFm2xCpurkQr9aPXv5/jpN+LfCwDaeI8rngVWtQZTx4qqbhc5zJspnLHJ4N/25KvDQ==
+pretender@^3.0.1:
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/pretender/-/pretender-3.0.4.tgz#e99fb39ae2b67ec7c1a2d0fc8f0cc63d4a8e9aff"
+ integrity sha512-l8geJ6tbBAe9Dl7a5aMKi5nYTabTci/wYBGA1MVVYfq1wLpBe+KYZM3YW+IvXuH4L/Vt1+zudmyigzFAuoWdDg==
dependencies:
- "@xg-wang/whatwg-fetch" "^3.0.0"
fake-xml-http-request "^2.0.0"
route-recognizer "^0.3.3"
+ whatwg-fetch "^3.0.0"
prettier-linter-helpers@^1.0.0:
version "1.0.0"
@@ -14188,3 +14280,8 @@ yuidocjs@^0.10.0:
minimatch "^3.0.2"
rimraf "^2.4.1"
yui "^3.18.1"
+
+zlib@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/zlib/-/zlib-1.0.5.tgz#6e7c972fc371c645a6afb03ab14769def114fcc0"
+ integrity sha1-bnyXL8NxxkWmr7A6sUdp3vEU/MA=