Skip to content

Commit

Permalink
Consolidate all has modules into single has module (#182)
Browse files Browse the repository at this point in the history
* Move all has checks to single has module

* clean up
  • Loading branch information
agubler committed Nov 26, 2018
1 parent 8bc723d commit 19dfbd3
Show file tree
Hide file tree
Showing 30 changed files with 393 additions and 466 deletions.
360 changes: 337 additions & 23 deletions src/has/has.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import global from '../shim/global';
import { Require, Config } from './loader';

/**
Expand Down Expand Up @@ -54,31 +55,12 @@ declare global {
}
}

/**
* A reference to the global scope (`window` in a browser, `global` in NodeJS)
*/
const globalScope = (function(): any {
/* istanbul ignore else */
if (typeof window !== 'undefined') {
// Browsers
return window;
} else if (typeof global !== 'undefined') {
// Node
return global;
} else if (typeof self !== 'undefined') {
// Web workers
return self;
}
/* istanbul ignore next */
return {};
})();

/* Grab the staticFeatures if there are available */
const { staticFeatures }: DojoHasEnvironment = globalScope.DojoHasEnvironment || {};
const { staticFeatures }: DojoHasEnvironment = global.DojoHasEnvironment || {};

/* Cleaning up the DojoHasEnviornment */
if ('DojoHasEnvironment' in globalScope) {
delete globalScope.DojoHasEnvironment;
if ('DojoHasEnvironment' in global) {
delete global.DojoHasEnvironment;
}

/**
Expand All @@ -97,7 +79,7 @@ function isStaticFeatureFunction(value: any): value is (() => StaticHasFeatures)
*/
const staticCache: StaticHasFeatures = staticFeatures
? isStaticFeatureFunction(staticFeatures)
? staticFeatures.apply(globalScope)
? staticFeatures.apply(global)
: staticFeatures
: {}; /* Providing an empty cache, if none was in the environment
Expand Down Expand Up @@ -261,3 +243,335 @@ add('host-node', function() {
return process.versions.node;
}
});

add('object-assign', typeof global.Object.assign === 'function', true);

add('arraybuffer', typeof global.ArrayBuffer !== 'undefined', true);
add('formdata', typeof global.FormData !== 'undefined', true);
add('filereader', typeof global.FileReader !== 'undefined', true);
add('xhr', typeof global.XMLHttpRequest !== 'undefined', true);
add('xhr2', has('xhr') && 'responseType' in global.XMLHttpRequest.prototype, true);
add(
'blob',
function() {
if (!has('xhr2')) {
return false;
}

const request = new global.XMLHttpRequest();
request.open('GET', global.location.protocol + '//www.google.com', true);
request.responseType = 'blob';
request.abort();
return request.responseType === 'blob';
},
true
);

add('node-buffer', 'Buffer' in global && typeof global.Buffer === 'function', true);

add('fetch', 'fetch' in global && typeof global.fetch === 'function', true);

add(
'web-worker-xhr-upload',
typeof global.Promise !== 'undefined' &&
new Promise((resolve) => {
try {
if (global.Worker !== undefined && global.URL && global.URL.createObjectURL) {
const blob = new Blob(
[
`(function () {
self.addEventListener('message', function () {
var xhr = new XMLHttpRequest();
try {
xhr.upload;
postMessage('true');
} catch (e) {
postMessage('false');
}
});
})()`
],
{ type: 'application/javascript' }
);
const worker = new Worker(URL.createObjectURL(blob));
worker.addEventListener('message', ({ data: result }) => {
resolve(result === 'true');
});
worker.postMessage({});
} else {
resolve(false);
}
} catch (e) {
// IE11 on Winodws 8.1 encounters a security error.
resolve(false);
}
}),
true
);

add(
'es6-array',
() => {
return (
['from', 'of'].every((key) => key in global.Array) &&
['findIndex', 'find', 'copyWithin'].every((key) => key in global.Array.prototype)
);
},
true
);

add(
'es6-array-fill',
() => {
if ('fill' in global.Array.prototype) {
/* Some versions of Safari do not properly implement this */
return ([1] as any).fill(9, Number.POSITIVE_INFINITY)[0] === 1;
}
return false;
},
true
);

add('es7-array', () => 'includes' in global.Array.prototype, true);

/* Map */
add(
'es6-map',
() => {
if (typeof global.Map === 'function') {
/*
IE11 and older versions of Safari are missing critical ES6 Map functionality
We wrap this in a try/catch because sometimes the Map constructor exists, but does not
take arguments (iOS 8.4)
*/
try {
const map = new global.Map([[0, 1]]);

return (
map.has(0) &&
typeof map.keys === 'function' &&
has('es6-symbol') &&
typeof map.values === 'function' &&
typeof map.entries === 'function'
);
} catch (e) {
/* istanbul ignore next: not testing on iOS at the moment */
return false;
}
}
return false;
},
true
);

/* Math */
add(
'es6-math',
() => {
return [
'clz32',
'sign',
'log10',
'log2',
'log1p',
'expm1',
'cosh',
'sinh',
'tanh',
'acosh',
'asinh',
'atanh',
'trunc',
'fround',
'cbrt',
'hypot'
].every((name) => typeof global.Math[name] === 'function');
},
true
);

add(
'es6-math-imul',
() => {
if ('imul' in global.Math) {
/* Some versions of Safari on ios do not properly implement this */
return (Math as any).imul(0xffffffff, 5) === -5;
}
return false;
},
true
);

/* Object */
add(
'es6-object',
() => {
return (
has('es6-symbol') &&
['assign', 'is', 'getOwnPropertySymbols', 'setPrototypeOf'].every(
(name) => typeof global.Object[name] === 'function'
)
);
},
true
);

add(
'es2017-object',
() => {
return ['values', 'entries', 'getOwnPropertyDescriptors'].every(
(name) => typeof global.Object[name] === 'function'
);
},
true
);

/* Observable */
add('es-observable', () => typeof global.Observable !== 'undefined', true);

/* Promise */
add('es6-promise', () => typeof global.Promise !== 'undefined' && has('es6-symbol'), true);

add(
'es2018-promise-finally',
() => has('es6-promise') && typeof global.Promise.prototype.finally !== 'undefined',
true
);

/* Set */
add(
'es6-set',
() => {
if (typeof global.Set === 'function') {
/* IE11 and older versions of Safari are missing critical ES6 Set functionality */
const set = new global.Set([1]);
return set.has(1) && 'keys' in set && typeof set.keys === 'function' && has('es6-symbol');
}
return false;
},
true
);

/* String */
add(
'es6-string',
() => {
return (
[
/* static methods */
'fromCodePoint'
].every((key) => typeof global.String[key] === 'function') &&
[
/* instance methods */
'codePointAt',
'normalize',
'repeat',
'startsWith',
'endsWith',
'includes'
].every((key) => typeof global.String.prototype[key] === 'function')
);
},
true
);

add(
'es6-string-raw',
() => {
function getCallSite(callSite: TemplateStringsArray, ...substitutions: any[]) {
const result = [...callSite];
(result as any).raw = callSite.raw;
return result;
}

if ('raw' in global.String) {
let b = 1;
let callSite = getCallSite`a\n${b}`;

(callSite as any).raw = ['a\\n'];
const supportsTrunc = global.String.raw(callSite, 42) === 'a\\n';

return supportsTrunc;
}

return false;
},
true
);

add(
'es2017-string',
() => {
return ['padStart', 'padEnd'].every((key) => typeof global.String.prototype[key] === 'function');
},
true
);

/* Symbol */
add('es6-symbol', () => typeof global.Symbol !== 'undefined' && typeof Symbol() === 'symbol', true);

/* WeakMap */
add(
'es6-weakmap',
() => {
if (typeof global.WeakMap !== 'undefined') {
/* IE11 and older versions of Safari are missing critical ES6 Map functionality */
const key1 = {};
const key2 = {};
const map = new global.WeakMap([[key1, 1]]);
Object.freeze(key1);
return map.get(key1) === 1 && map.set(key2, 2) === map && has('es6-symbol');
}
return false;
},
true
);

/* Miscellaneous features */
add('microtasks', () => has('es6-promise') || has('host-node') || has('dom-mutationobserver'), true);
add(
'postmessage',
() => {
// If window is undefined, and we have postMessage, it probably means we're in a web worker. Web workers have
// post message but it doesn't work how we expect it to, so it's best just to pretend it doesn't exist.
return typeof global.window !== 'undefined' && typeof global.postMessage === 'function';
},
true
);
add('raf', () => typeof global.requestAnimationFrame === 'function', true);
add('setimmediate', () => typeof global.setImmediate !== 'undefined', true);

/* DOM Features */

add(
'dom-mutationobserver',
() => {
if (has('host-browser') && Boolean(global.MutationObserver || global.WebKitMutationObserver)) {
// IE11 has an unreliable MutationObserver implementation where setProperty() does not
// generate a mutation event, observers can crash, and the queue does not drain
// reliably. The following feature test was adapted from
// https://gist.github.com/t10ko/4aceb8c71681fdb275e33efe5e576b14
const example = document.createElement('div');
/* tslint:disable-next-line:variable-name */
const HostMutationObserver = global.MutationObserver || global.WebKitMutationObserver;
const observer = new HostMutationObserver(function() {});
observer.observe(example, { attributes: true });

example.style.setProperty('display', 'block');

return Boolean(observer.takeRecords().length);
}
return false;
},
true
);

add(
'dom-webanimation',
() => has('host-browser') && global.Animation !== undefined && global.KeyframeEffect !== undefined,
true
);

add('abort-controller', () => typeof global.AbortController !== 'undefined');

add('abort-signal', () => typeof global.AbortSignal !== 'undefined');
3 changes: 0 additions & 3 deletions src/has/main.ts

This file was deleted.

Loading

0 comments on commit 19dfbd3

Please sign in to comment.