diff --git a/addon/-private/index.js b/addon/-private/index.js index cc9b9b706b3..d751a7ac8a6 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -53,3 +53,8 @@ export { default as DebugAdapter } from './system/debug/debug-adapter'; // Used by tests export { default as diffArray } from './system/diff-array'; export { default as SnapshotRecordArray } from './system/snapshot-record-array'; + +// fetch support, used by rest adapter +export { determineBodyPromise } from './utils/determine-body-promise'; +export { serializeQueryParams } from './utils/serialize-query-params'; +export { default as fetch } from './utils/fetch'; diff --git a/addon/-private/utils/determine-body-promise.ts b/addon/-private/utils/determine-body-promise.ts new file mode 100644 index 00000000000..a1fba5c9fb9 --- /dev/null +++ b/addon/-private/utils/determine-body-promise.ts @@ -0,0 +1,30 @@ +/** + * Function that always attempts to parse the response as json, and if an error is thrown, + * returns `undefined` if the response is successful and has a status code of 204 (No Content), + * or 205 (Reset Content) or if the request method was 'HEAD', and the plain payload otherwise. + */ +export function determineBodyPromise( + response: Response, + requestData: JQueryAjaxSettings +): Promise { + return response.text().then(function(payload) { + let ret: string | object | undefined = payload; + try { + ret = JSON.parse(payload); + } catch (error) { + if (!(error instanceof SyntaxError)) { + throw error; + } + const status = response.status; + if ( + response.ok && + (status === 204 || status === 205 || requestData.method === 'HEAD') + ) { + ret = undefined; + } else { + console.warn('This response was unable to be parsed as json.', payload); + } + } + return ret; + }); +} diff --git a/addon/-private/utils/fetch.ts b/addon/-private/utils/fetch.ts new file mode 100644 index 00000000000..dbb6363fe31 --- /dev/null +++ b/addon/-private/utils/fetch.ts @@ -0,0 +1,17 @@ +import require, { has } from 'require'; + + type MaybeFetch = { + (input: RequestInfo, init?: RequestInit | undefined): Promise; +} | null; + + let _fetch: MaybeFetch = null; + + if (has('fetch')) { + // use `fetch` module by default, this is commonly provided by ember-fetch + _fetch = require('fetch').default; +} else if (typeof fetch === 'function') { + // fallback to using global fetch + _fetch = fetch; +} + + export default _fetch; diff --git a/addon/-private/utils/serialize-query-params.ts b/addon/-private/utils/serialize-query-params.ts new file mode 100644 index 00000000000..4677108ea5b --- /dev/null +++ b/addon/-private/utils/serialize-query-params.ts @@ -0,0 +1,69 @@ +const RBRACKET = /\[\]$/; + + function isPlainObject(obj: any): boolean { + return Object.prototype.toString.call(obj) === '[object Object]'; +} + + /** + * Helper function that turns the data/body of a request into a query param string. + * This is directly copied from jQuery.param. + */ +export function serializeQueryParams( + queryParamsObject: object | string +): string { + var s: any[] = []; + + function buildParams(prefix: string, obj: any) { + var i, len, key; + + if (prefix) { + if (Array.isArray(obj)) { + for (i = 0, len = obj.length; i < len; i++) { + if (RBRACKET.test(prefix)) { + add(s, prefix, obj[i]); + } else { + buildParams( + prefix + '[' + (typeof obj[i] === 'object' ? i : '') + ']', + obj[i] + ); + } + } + } else if (isPlainObject(obj)) { + for (key in obj) { + buildParams(prefix + '[' + key + ']', obj[key]); + } + } else { + add(s, prefix, obj); + } + } else if (Array.isArray(obj)) { + for (i = 0, len = obj.length; i < len; i++) { + add(s, obj[i].name, obj[i].value); + } + } else { + for (key in obj) { + buildParams(key, obj[key]); + } + } + return s; + } + + return buildParams('', queryParamsObject) + .join('&') + .replace(/%20/g, '+'); +} + + /** + * Part of the `serializeQueryParams` helper function. + */ +function add(s: Array, k: string, v?: string | (() => string)) { + // Strip out keys with undefined value and replace null values with + // empty strings (mimics jQuery.ajax) + if (v === undefined) { + return; + } else if (v === null) { + v = ''; + } + + v = typeof v === 'function' ? v() : v; + s[s.length] = `${encodeURIComponent(k)}=${encodeURIComponent(v)}`; +} diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index bd53ae6700e..695b794325e 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -4,10 +4,6 @@ @module ember-data */ -import fetch from 'fetch'; -import serializeQueryParams from 'ember-fetch/utils/serialize-query-params'; -import determineBodyPromise from 'ember-fetch/utils/determine-body-promise'; - import RSVP, { Promise as EmberPromise } from 'rsvp'; import { get, computed } from '@ember/object'; import { getOwner } from '@ember/application'; @@ -26,7 +22,11 @@ import { ServerError, TimeoutError, AbortError, + determineBodyPromise, + fetch, + serializeQueryParams, } from '../-private'; + import { warn } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; @@ -303,7 +303,9 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { useFetch: computed(function() { let ENV = getOwner(this).resolveRegistration('config:environment'); - return (ENV && ENV._JQUERY_INTEGRATION) === false || jQ === undefined; + let shouldUseFetch = (ENV && ENV._JQUERY_INTEGRATION) === false || jQ === undefined; + + return shouldUseFetch; }), /** diff --git a/index.js b/index.js index 22b0a41bacc..0be826f8378 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,6 @@ const version = require('./lib/version'); const { isInstrumentedBuild } = require('./lib/cli-flags'); const BroccoliDebug = require('broccoli-debug'); const calculateCacheKeyForTree = require('calculate-cache-key-for-tree'); -const resolve = require('resolve'); function isProductionEnv() { let isProd = /production/.test(process.env.EMBER_ENV); @@ -70,19 +69,6 @@ module.exports = { return path.join(__dirname, 'blueprints'); }, - updateFastBootManifest(manifest) { - manifest.vendorFiles.push('ember-data/fetch-fastboot.js'); - return manifest; - }, - - treeForPublic() { - let fetchPath = resolve.sync('ember-fetch'); - - return new Funnel(path.join(path.dirname(fetchPath), 'public'), { - destDir: 'ember-data', - }); - }, - treeForAddon(tree) { tree = this.debugTree(tree, 'input'); this._setupBabelOptions(); diff --git a/package.json b/package.json index f20cb93e21b..4f0673af381 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "ember-cli-test-info": "^1.0.0", "ember-cli-typescript": "^2.0.0", "ember-cli-version-checker": "^3.1.3", - "ember-fetch": "^6.5.0", "ember-inflector": "^3.0.0", "git-repo-info": "^2.0.0", "heimdalljs": "^0.3.0", @@ -133,11 +132,6 @@ "ember-addon" ], "ember-addon": { - "configPath": "tests/dummy/config", - "fastbootDependencies": [ - "node-fetch", - "abortcontroller-polyfill", - "abortcontroller-polyfill/dist/cjs-ponyfill" - ] + "configPath": "tests/dummy/config" } } diff --git a/yarn.lock b/yarn.lock index 62e25c04152..853aae69468 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1083,7 +1083,7 @@ abbrev@1: resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abortcontroller-polyfill@^1.1.9, abortcontroller-polyfill@^1.2.5: +abortcontroller-polyfill@^1.1.9: version "1.2.9" resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.2.9.tgz#402311d2aac7e8e093ecb045726b45fdafd834fe" integrity sha512-0goWhDrwoWtK6XCdFdzPtvHBmmQU91j3tULNL85MAnDuM7bNlzUDfmL5AZGL819L7pn9kra35HJGWG25UgRCBw== @@ -2234,7 +2234,7 @@ broccoli-clean-css@^1.1.0: inline-source-map-comment "^1.0.5" json-stable-stringify "^1.0.0" -broccoli-concat@^3.2.2, broccoli-concat@^3.7.3: +broccoli-concat@^3.7.3: version "3.7.3" resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.7.3.tgz#0dca01311567ffb13180e6b4eb111824628e4885" integrity sha512-2Ma9h81EJ0PRb9n4sW0i8KZlcnpTQfKxcj87zvi5DFe1fd8CTDEdseHDotK2beuA2l+LbgVPfd8EHaBJKm/Y8g== @@ -2560,17 +2560,6 @@ broccoli-string-replace@^0.1.2: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" -broccoli-templater@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/broccoli-templater/-/broccoli-templater-2.0.2.tgz#285a892071c0b3ad5ebc275d9e8b3465e2d120d6" - integrity sha512-71KpNkc7WmbEokTQpGcbGzZjUIY1NSVa3GB++KFKAfx5SZPUozCOsBlSTwxcv8TLoCAqbBnsX5AQPgg6vJ2l9g== - dependencies: - broccoli-plugin "^1.3.1" - fs-tree-diff "^0.5.9" - lodash.template "^4.4.0" - rimraf "^2.6.2" - walk-sync "^0.3.3" - broccoli-test-helper@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/broccoli-test-helper/-/broccoli-test-helper-2.0.0.tgz#1cfbb76f7e856ad8df96d55ee2f5e0dddddf5d4f" @@ -2655,7 +2644,7 @@ browserslist@^3.2.6: caniuse-lite "^1.0.30000844" electron-to-chromium "^1.3.47" -browserslist@^4.0.0, browserslist@^4.3.4: +browserslist@^4.3.4: version "4.4.2" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.4.2.tgz#6ea8a74d6464bb0bd549105f659b41197d8f0ba2" integrity sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg== @@ -2766,17 +2755,7 @@ can-symlink@^1.0.0: dependencies: tmp "0.0.28" -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000939: +caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000939: version "1.0.30000942" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000942.tgz#454139b28274bce70bfe1d50c30970df7430c6e4" integrity sha512-wLf+IhZUy2rfz48tc40OH7jHjXjnvDFEYqBHluINs/6MgzoNLPf25zhE4NOVzqxLKndf+hau81sAW0RcGHIaBQ== @@ -3466,7 +3445,7 @@ ember-cli-babel-plugin-helpers@^1.0.0, ember-cli-babel-plugin-helpers@^1.1.0: resolved "https://registry.yarnpkg.com/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.1.0.tgz#de3baedd093163b6c2461f95964888c1676325ac" integrity sha512-Zr4my8Xn+CzO0gIuFNXji0eTRml5AxZUTDQz/wsNJ5AJAtyFWCY4QtKdoELNNbiCVGt1lq5yLiwTm4scGKu6xA== -ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: +ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.9.0: version "6.18.0" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz#3f6435fd275172edeff2b634ee7b29ce74318957" integrity sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA== @@ -3894,24 +3873,6 @@ ember-export-application-global@^2.0.0: dependencies: ember-cli-babel "^6.0.0-beta.7" -ember-fetch@^6.5.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/ember-fetch/-/ember-fetch-6.5.0.tgz#efed80b3dd2259b52efce7498659e9125235bfb7" - integrity sha512-B9KSeeO3xDNMQ22JqNwbmgnOprBzc8kNVfQMtzkAmugMb2aCmBZohAlQlwUUX5ODz8fHq2xfuZXDHD81Dzb0vg== - dependencies: - abortcontroller-polyfill "^1.2.5" - broccoli-concat "^3.2.2" - broccoli-debug "^0.6.5" - broccoli-merge-trees "^3.0.0" - broccoli-rollup "^2.1.1" - broccoli-stew "^2.0.0" - broccoli-templater "^2.0.1" - calculate-cache-key-for-tree "^1.1.0" - caniuse-api "^3.0.0" - ember-cli-babel "^6.8.2" - node-fetch "^2.3.0" - whatwg-fetch "^3.0.0" - ember-inflector@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-3.0.0.tgz#7e1ee8aaa0fa773ba0905d8b7c0786354d890ee1" @@ -6256,11 +6217,6 @@ lodash.keys@~2.3.0: lodash._shimkeys "~2.3.0" lodash.isobject "~2.3.0" -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - lodash.merge@^4.3.1, lodash.merge@^4.6.0: version "4.6.1" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" @@ -6324,7 +6280,7 @@ lodash.templatesettings@~2.3.0: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" -lodash.uniq@^4.2.0, lodash.uniq@^4.5.0: +lodash.uniq@^4.2.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= @@ -6750,11 +6706,6 @@ node-environment-flags@1.0.4: dependencies: object.getownpropertydescriptors "^2.0.3" -node-fetch@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" - integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"