@lumino/coreutils
Version:
Lumino Core Utilities
1,051 lines (1,040 loc) • 36 kB
JavaScript
import { topologicSort } from '@lumino/algorithm';
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* The namespace for JSON-specific functions.
*/
var JSONExt;
(function (JSONExt) {
/**
* A shared frozen empty JSONObject
*/
JSONExt.emptyObject = Object.freeze({});
/**
* A shared frozen empty JSONArray
*/
JSONExt.emptyArray = Object.freeze([]);
/**
* Test whether a JSON value is a primitive.
*
* @param value - The JSON value of interest.
*
* @returns `true` if the value is a primitive,`false` otherwise.
*/
function isPrimitive(value) {
return (value === null ||
typeof value === 'boolean' ||
typeof value === 'number' ||
typeof value === 'string');
}
JSONExt.isPrimitive = isPrimitive;
function isArray(value) {
return Array.isArray(value);
}
JSONExt.isArray = isArray;
function isObject(value) {
return !isPrimitive(value) && !isArray(value);
}
JSONExt.isObject = isObject;
/**
* Compare two JSON values for deep equality.
*
* @param first - The first JSON value of interest.
*
* @param second - The second JSON value of interest.
*
* @returns `true` if the values are equivalent, `false` otherwise.
*/
function deepEqual(first, second) {
// Check referential and primitive equality first.
if (first === second) {
return true;
}
// If one is a primitive, the `===` check ruled out the other.
if (isPrimitive(first) || isPrimitive(second)) {
return false;
}
// Test whether they are arrays.
let a1 = isArray(first);
let a2 = isArray(second);
// Bail if the types are different.
if (a1 !== a2) {
return false;
}
// If they are both arrays, compare them.
if (a1 && a2) {
return deepArrayEqual(first, second);
}
// At this point, they must both be objects.
return deepObjectEqual(first, second);
}
JSONExt.deepEqual = deepEqual;
/**
* Create a deep copy of a JSON value.
*
* @param value - The JSON value to copy.
*
* @returns A deep copy of the given JSON value.
*/
function deepCopy(value) {
// Do nothing for primitive values.
if (isPrimitive(value)) {
return value;
}
// Deep copy an array.
if (isArray(value)) {
return deepArrayCopy(value);
}
// Deep copy an object.
return deepObjectCopy(value);
}
JSONExt.deepCopy = deepCopy;
/**
* Compare two JSON arrays for deep equality.
*/
function deepArrayEqual(first, second) {
// Check referential equality first.
if (first === second) {
return true;
}
// Test the arrays for equal length.
if (first.length !== second.length) {
return false;
}
// Compare the values for equality.
for (let i = 0, n = first.length; i < n; ++i) {
if (!deepEqual(first[i], second[i])) {
return false;
}
}
// At this point, the arrays are equal.
return true;
}
/**
* Compare two JSON objects for deep equality.
*/
function deepObjectEqual(first, second) {
// Check referential equality first.
if (first === second) {
return true;
}
// Check for the first object's keys in the second object.
for (let key in first) {
if (first[key] !== undefined && !(key in second)) {
return false;
}
}
// Check for the second object's keys in the first object.
for (let key in second) {
if (second[key] !== undefined && !(key in first)) {
return false;
}
}
// Compare the values for equality.
for (let key in first) {
// Get the values.
let firstValue = first[key];
let secondValue = second[key];
// If both are undefined, ignore the key.
if (firstValue === undefined && secondValue === undefined) {
continue;
}
// If only one value is undefined, the objects are not equal.
if (firstValue === undefined || secondValue === undefined) {
return false;
}
// Compare the values.
if (!deepEqual(firstValue, secondValue)) {
return false;
}
}
// At this point, the objects are equal.
return true;
}
/**
* Create a deep copy of a JSON array.
*/
function deepArrayCopy(value) {
let result = new Array(value.length);
for (let i = 0, n = value.length; i < n; ++i) {
result[i] = deepCopy(value[i]);
}
return result;
}
/**
* Create a deep copy of a JSON object.
*/
function deepObjectCopy(value) {
let result = {};
for (let key in value) {
// Ignore undefined values.
let subvalue = value[key];
if (subvalue === undefined) {
continue;
}
result[key] = deepCopy(subvalue);
}
return result;
}
})(JSONExt || (JSONExt = {}));
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* An object which stores MIME data for general application use.
*
* #### Notes
* This class does not attempt to enforce "correctness" of MIME types
* and their associated data. Since this class is designed to transfer
* arbitrary data and objects within the same application, it assumes
* that the user provides correct and accurate data.
*/
class MimeData {
constructor() {
this._types = [];
this._values = [];
}
/**
* Get an array of the MIME types contained within the dataset.
*
* @returns A new array of the MIME types, in order of insertion.
*/
types() {
return this._types.slice();
}
/**
* Test whether the dataset has an entry for the given type.
*
* @param mime - The MIME type of interest.
*
* @returns `true` if the dataset contains a value for the given
* MIME type, `false` otherwise.
*/
hasData(mime) {
return this._types.indexOf(mime) !== -1;
}
/**
* Get the data value for the given MIME type.
*
* @param mime - The MIME type of interest.
*
* @returns The value for the given MIME type, or `undefined` if
* the dataset does not contain a value for the type.
*/
getData(mime) {
let i = this._types.indexOf(mime);
return i !== -1 ? this._values[i] : undefined;
}
/**
* Set the data value for the given MIME type.
*
* @param mime - The MIME type of interest.
*
* @param data - The data value for the given MIME type.
*
* #### Notes
* This will overwrite any previous entry for the MIME type.
*/
setData(mime, data) {
this.clearData(mime);
this._types.push(mime);
this._values.push(data);
}
/**
* Remove the data entry for the given MIME type.
*
* @param mime - The MIME type of interest.
*
* #### Notes
* This is a no-op if there is no entry for the given MIME type.
*/
clearData(mime) {
let i = this._types.indexOf(mime);
if (i !== -1) {
this._types.splice(i, 1);
this._values.splice(i, 1);
}
}
/**
* Remove all data entries from the dataset.
*/
clear() {
this._types.length = 0;
this._values.length = 0;
}
}
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/**
* Plugin registry.
*/
class PluginRegistry {
constructor(options = {}) {
this._application = null;
this._validatePlugin = () => true;
this._plugins = new Map();
this._services = new Map();
if (options.validatePlugin) {
console.info('Plugins may be rejected by the custom validation plugin method.');
this._validatePlugin = options.validatePlugin;
}
}
/**
* The application object.
*
* It will be provided as first argument to the
* plugins activation and deactivation functions.
*
* It can only be set once.
*
* By default, it is `null`.
*/
get application() {
return this._application;
}
set application(v) {
if (this._application !== null) {
throw Error('PluginRegistry.application is already set. It cannot be overridden.');
}
this._application = v;
}
/**
* The list of all the deferred plugins.
*/
get deferredPlugins() {
return Array.from(this._plugins)
.filter(([id, plugin]) => plugin.autoStart === 'defer')
.map(([id, plugin]) => id);
}
/**
* Get a plugin description.
*
* @param id - The ID of the plugin of interest.
*
* @returns The plugin description.
*/
getPluginDescription(id) {
var _a, _b;
return (_b = (_a = this._plugins.get(id)) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : '';
}
/**
* Test whether a plugin is registered with the application.
*
* @param id - The ID of the plugin of interest.
*
* @returns `true` if the plugin is registered, `false` otherwise.
*/
hasPlugin(id) {
return this._plugins.has(id);
}
/**
* Test whether a plugin is activated with the application.
*
* @param id - The ID of the plugin of interest.
*
* @returns `true` if the plugin is activated, `false` otherwise.
*/
isPluginActivated(id) {
var _a, _b;
return (_b = (_a = this._plugins.get(id)) === null || _a === void 0 ? void 0 : _a.activated) !== null && _b !== void 0 ? _b : false;
}
/**
* List the IDs of the plugins registered with the application.
*
* @returns A new array of the registered plugin IDs.
*/
listPlugins() {
return Array.from(this._plugins.keys());
}
/**
* Register a plugin with the application.
*
* @param plugin - The plugin to register.
*
* #### Notes
* An error will be thrown if a plugin with the same ID is already
* registered, or if the plugin has a circular dependency.
*
* If the plugin provides a service which has already been provided
* by another plugin, the new service will override the old service.
*/
registerPlugin(plugin) {
// Throw an error if the plugin ID is already registered.
if (this._plugins.has(plugin.id)) {
throw new TypeError(`Plugin '${plugin.id}' is already registered.`);
}
if (!this._validatePlugin(plugin)) {
throw new Error(`Plugin '${plugin.id}' is not valid.`);
}
// Create the normalized plugin data.
const data = Private.createPluginData(plugin);
// Ensure the plugin does not cause a cyclic dependency.
Private.ensureNoCycle(data, this._plugins, this._services);
// Add the service token to the service map.
if (data.provides) {
this._services.set(data.provides, data.id);
}
// Add the plugin to the plugin map.
this._plugins.set(data.id, data);
}
/**
* Register multiple plugins with the application.
*
* @param plugins - The plugins to register.
*
* #### Notes
* This calls `registerPlugin()` for each of the given plugins.
*/
registerPlugins(plugins) {
for (const plugin of plugins) {
this.registerPlugin(plugin);
}
}
/**
* Deregister a plugin with the application.
*
* @param id - The ID of the plugin of interest.
*
* @param force - Whether to deregister the plugin even if it is active.
*/
deregisterPlugin(id, force) {
const plugin = this._plugins.get(id);
if (!plugin) {
return;
}
if (plugin.activated && !force) {
throw new Error(`Plugin '${id}' is still active.`);
}
this._plugins.delete(id);
}
/**
* Activate the plugin with the given ID.
*
* @param id - The ID of the plugin of interest.
*
* @returns A promise which resolves when the plugin is activated
* or rejects with an error if it cannot be activated.
*/
async activatePlugin(id) {
// Reject the promise if the plugin is not registered.
const plugin = this._plugins.get(id);
if (!plugin) {
throw new ReferenceError(`Plugin '${id}' is not registered.`);
}
// Resolve immediately if the plugin is already activated.
if (plugin.activated) {
return;
}
// Return the pending resolver promise if it exists.
if (plugin.promise) {
return plugin.promise;
}
// Resolve the required services for the plugin.
const required = plugin.requires.map(t => this.resolveRequiredService(t));
// Resolve the optional services for the plugin.
const optional = plugin.optional.map(t => this.resolveOptionalService(t));
// Setup the resolver promise for the plugin.
plugin.promise = Promise.all([...required, ...optional])
.then(services => plugin.activate.apply(undefined, [this.application, ...services]))
.then(service => {
plugin.service = service;
plugin.activated = true;
plugin.promise = null;
})
.catch(error => {
plugin.promise = null;
throw error;
});
// Return the pending resolver promise.
return plugin.promise;
}
/**
* Activate all the deferred plugins.
*
* @returns A promise which will resolve when each plugin is activated
* or rejects with an error if one cannot be activated.
*/
async activatePlugins(kind, options = {}) {
switch (kind) {
case 'defer': {
const promises = this.deferredPlugins
.filter(pluginId => this._plugins.get(pluginId).autoStart)
.map(pluginId => {
return this.activatePlugin(pluginId);
});
await Promise.all(promises);
break;
}
case 'startUp': {
// Collect the ids of the startup plugins.
const startups = Private.collectStartupPlugins(this._plugins, options);
// Generate the activation promises.
const promises = startups.map(async (id) => {
try {
return await this.activatePlugin(id);
}
catch (error) {
console.error(`Plugin '${id}' failed to activate.`, error);
}
});
await Promise.all(promises);
break;
}
}
}
/**
* Deactivate the plugin and its downstream dependents if and only if the
* plugin and its dependents all support `deactivate`.
*
* @param id - The ID of the plugin of interest.
*
* @returns A list of IDs of downstream plugins deactivated with this one.
*/
async deactivatePlugin(id) {
// Reject the promise if the plugin is not registered.
const plugin = this._plugins.get(id);
if (!plugin) {
throw new ReferenceError(`Plugin '${id}' is not registered.`);
}
// Bail early if the plugin is not activated.
if (!plugin.activated) {
return [];
}
// Check that this plugin can deactivate.
if (!plugin.deactivate) {
throw new TypeError(`Plugin '${id}'#deactivate() method missing`);
}
// Find the optimal deactivation order for plugins downstream of this one.
const manifest = Private.findDependents(id, this._plugins, this._services);
const downstream = manifest.map(id => this._plugins.get(id));
// Check that all downstream plugins can deactivate.
for (const plugin of downstream) {
if (!plugin.deactivate) {
throw new TypeError(`Plugin ${plugin.id}#deactivate() method missing (depends on ${id})`);
}
}
// Deactivate all downstream plugins.
for (const plugin of downstream) {
const services = [...plugin.requires, ...plugin.optional].map(service => {
const id = this._services.get(service);
return id ? this._plugins.get(id).service : null;
});
// Await deactivation so the next plugins only receive active services.
await plugin.deactivate(this.application, ...services);
plugin.service = null;
plugin.activated = false;
}
// Remove plugin ID and return manifest of deactivated plugins.
manifest.pop();
return manifest;
}
/**
* Resolve a required service of a given type.
*
* @param token - The token for the service type of interest.
*
* @returns A promise which resolves to an instance of the requested
* service, or rejects with an error if it cannot be resolved.
*
* #### Notes
* Services are singletons. The same instance will be returned each
* time a given service token is resolved.
*
* If the plugin which provides the service has not been activated,
* resolving the service will automatically activate the plugin.
*
* User code will not typically call this method directly. Instead,
* the required services for the user's plugins will be resolved
* automatically when the plugin is activated.
*/
async resolveRequiredService(token) {
// Reject the promise if there is no provider for the type.
const id = this._services.get(token);
if (!id) {
throw new TypeError(`No provider for: ${token.name}.`);
}
// Activate the plugin if necessary.
const plugin = this._plugins.get(id);
if (!plugin.activated) {
await this.activatePlugin(id);
}
return plugin.service;
}
/**
* Resolve an optional service of a given type.
*
* @param token - The token for the service type of interest.
*
* @returns A promise which resolves to an instance of the requested
* service, or `null` if it cannot be resolved.
*
* #### Notes
* Services are singletons. The same instance will be returned each
* time a given service token is resolved.
*
* If the plugin which provides the service has not been activated,
* resolving the service will automatically activate the plugin.
*
* User code will not typically call this method directly. Instead,
* the optional services for the user's plugins will be resolved
* automatically when the plugin is activated.
*/
async resolveOptionalService(token) {
// Resolve with `null` if there is no provider for the type.
const id = this._services.get(token);
if (!id) {
return null;
}
// Activate the plugin if necessary.
const plugin = this._plugins.get(id);
if (!plugin.activated) {
try {
await this.activatePlugin(id);
}
catch (reason) {
console.error(reason);
return null;
}
}
return plugin.service;
}
}
/**
* The namespace for the module implementation details.
*/
var Private;
(function (Private) {
class PluginData {
constructor(plugin) {
var _a, _b, _c, _d;
this._activated = false;
this._promise = null;
this._service = null;
this.id = plugin.id;
this.description = (_a = plugin.description) !== null && _a !== void 0 ? _a : '';
this.activate = plugin.activate;
this.deactivate = (_b = plugin.deactivate) !== null && _b !== void 0 ? _b : null;
this.provides = (_c = plugin.provides) !== null && _c !== void 0 ? _c : null;
this.autoStart = (_d = plugin.autoStart) !== null && _d !== void 0 ? _d : false;
this.requires = plugin.requires ? plugin.requires.slice() : [];
this.optional = plugin.optional ? plugin.optional.slice() : [];
}
/**
* Whether the plugin has been activated.
*/
get activated() {
return this._activated;
}
set activated(a) {
this._activated = a;
}
/**
* The resolved service for the plugin, or `null`.
*/
get service() {
return this._service;
}
set service(s) {
this._service = s;
}
/**
* The pending resolver promise, or `null`.
*/
get promise() {
return this._promise;
}
set promise(p) {
this._promise = p;
}
}
/**
* Create a normalized plugin data object for the given plugin.
*/
function createPluginData(plugin) {
return new PluginData(plugin);
}
Private.createPluginData = createPluginData;
/**
* Ensure no cycle is present in the plugin resolution graph.
*
* If a cycle is detected, an error will be thrown.
*/
function ensureNoCycle(plugin, plugins, services) {
const dependencies = [...plugin.requires, ...plugin.optional];
const visit = (token) => {
if (token === plugin.provides) {
return true;
}
const id = services.get(token);
if (!id) {
return false;
}
const visited = plugins.get(id);
const dependencies = [...visited.requires, ...visited.optional];
if (dependencies.length === 0) {
return false;
}
trace.push(id);
if (dependencies.some(visit)) {
return true;
}
trace.pop();
return false;
};
// Bail early if there cannot be a cycle.
if (!plugin.provides || dependencies.length === 0) {
return;
}
// Setup a stack to trace service resolution.
const trace = [plugin.id];
// Throw an exception if a cycle is present.
if (dependencies.some(visit)) {
throw new ReferenceError(`Cycle detected: ${trace.join(' -> ')}.`);
}
}
Private.ensureNoCycle = ensureNoCycle;
/**
* Find dependents in deactivation order.
*
* @param id - The ID of the plugin of interest.
*
* @param plugins - The map containing all plugins.
*
* @param services - The map containing all services.
*
* @returns A list of dependent plugin IDs in order of deactivation
*
* #### Notes
* The final item of the returned list is always the plugin of interest.
*/
function findDependents(id, plugins, services) {
const edges = new Array();
const add = (id) => {
const plugin = plugins.get(id);
// FIXME In the case of missing optional dependencies, we may consider
// deactivating and reactivating the plugin without the missing service.
const dependencies = [...plugin.requires, ...plugin.optional];
edges.push(...dependencies.reduce((acc, dep) => {
const service = services.get(dep);
if (service) {
// An edge is oriented from dependent to provider.
acc.push([id, service]);
}
return acc;
}, []));
};
for (const id of plugins.keys()) {
add(id);
}
// Filter edges
// - Get all packages that dependent on the package to be deactivated
const newEdges = edges.filter(edge => edge[1] === id);
let oldSize = 0;
while (newEdges.length > oldSize) {
const previousSize = newEdges.length;
// Get all packages that dependent on packages that will be deactivated
const packagesOfInterest = new Set(newEdges.map(edge => edge[0]));
for (const poi of packagesOfInterest) {
edges
.filter(edge => edge[1] === poi)
.forEach(edge => {
// We check it is not already included to deal with circular dependencies
if (!newEdges.includes(edge)) {
newEdges.push(edge);
}
});
}
oldSize = previousSize;
}
const sorted = topologicSort(newEdges);
const index = sorted.findIndex(candidate => candidate === id);
if (index === -1) {
return [id];
}
return sorted.slice(0, index + 1);
}
Private.findDependents = findDependents;
/**
* Collect the IDs of the plugins to activate on startup.
*/
function collectStartupPlugins(plugins, options) {
// Create a set to hold the plugin IDs.
const collection = new Set();
// Collect the auto-start (non deferred) plugins.
for (const id of plugins.keys()) {
if (plugins.get(id).autoStart === true) {
collection.add(id);
}
}
// Add the startup plugins.
if (options.startPlugins) {
for (const id of options.startPlugins) {
collection.add(id);
}
}
// Remove the ignored plugins.
if (options.ignorePlugins) {
for (const id of options.ignorePlugins) {
collection.delete(id);
}
}
// Return the collected startup plugins.
return Array.from(collection);
}
Private.collectStartupPlugins = collectStartupPlugins;
})(Private || (Private = {}));
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* A class which wraps a promise into a delegate object.
*
* #### Notes
* This class is useful when the logic to resolve or reject a promise
* cannot be defined at the point where the promise is created.
*/
class PromiseDelegate {
/**
* Construct a new promise delegate.
*/
constructor() {
this.promise = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
}
/**
* Resolve the wrapped promise with the given value.
*
* @param value - The value to use for resolving the promise.
*/
resolve(value) {
let resolve = this._resolve;
resolve(value);
}
/**
* Reject the wrapped promise with the given value.
*
* @reason - The reason for rejecting the promise.
*/
reject(reason) {
let reject = this._reject;
reject(reason);
}
}
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* A runtime object which captures compile-time type information.
*
* #### Notes
* A token captures the compile-time type of an interface or class in
* an object which can be used at runtime in a type-safe fashion.
*/
class Token {
/**
* Construct a new token.
*
* @param name - A human readable name for the token.
* @param description - Token purpose description for documentation.
*/
constructor(name, description) {
this.name = name;
this.description = description !== null && description !== void 0 ? description : '';
this._tokenStructuralPropertyT = null;
}
}
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
// Fallback
function fallbackRandomValues(buffer) {
let value = 0;
for (let i = 0, n = buffer.length; i < n; ++i) {
if (i % 4 === 0) {
value = (Math.random() * 0xffffffff) >>> 0;
}
buffer[i] = value & 0xff;
value >>>= 8;
}
}
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* The namespace for random number related functionality.
*/
var Random;
(function (Random) {
/**
* A function which generates random bytes.
*
* @param buffer - The `Uint8Array` to fill with random bytes.
*
* #### Notes
* A cryptographically strong random number generator will be used if
* available. Otherwise, `Math.random` will be used as a fallback for
* randomness.
*
* The following RNGs are supported, listed in order of precedence:
* - `window.crypto.getRandomValues`
* - `window.msCrypto.getRandomValues`
* - `require('crypto').randomFillSync
* - `require('crypto').randomBytes
* - `Math.random`
*/
Random.getRandomValues = (() => {
// Look up the crypto module if available.
const crypto = (typeof require !== 'undefined' && require('crypto')) || null;
// Node 7+
if (crypto && typeof crypto.randomFillSync === 'function') {
return function getRandomValues(buffer) {
return crypto.randomFillSync(buffer);
};
}
// Node 0.10+
if (crypto && typeof crypto.randomBytes === 'function') {
return function getRandomValues(buffer) {
let bytes = crypto.randomBytes(buffer.length);
for (let i = 0, n = bytes.length; i < n; ++i) {
buffer[i] = bytes[i];
}
};
}
// Fallback
return fallbackRandomValues;
})();
})(Random || (Random = {}));
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* A function which creates a function that generates UUID v4 identifiers.
*
* @returns A new function that creates a UUID v4 string.
*
* #### Notes
* This implementation complies with RFC 4122.
*
* This uses `Random.getRandomValues()` for random bytes, which in
* turn will use the underlying `crypto` module of the platform if
* it is available. The fallback for randomness is `Math.random`.
*/
function uuid4Factory(getRandomValues) {
// Create a 16 byte array to hold the random values.
const bytes = new Uint8Array(16);
// Create a look up table from bytes to hex strings.
const lut = new Array(256);
// Pad the single character hex digits with a leading zero.
for (let i = 0; i < 16; ++i) {
lut[i] = '0' + i.toString(16);
}
// Populate the rest of the hex digits.
for (let i = 16; i < 256; ++i) {
lut[i] = i.toString(16);
}
// Return a function which generates the UUID.
return function uuid4() {
// Get a new batch of random values.
getRandomValues(bytes);
// Set the UUID version number to 4.
bytes[6] = 0x40 | (bytes[6] & 0x0f);
// Set the clock sequence bit to the RFC spec.
bytes[8] = 0x80 | (bytes[8] & 0x3f);
// Assemble the UUID string.
return (lut[bytes[0]] +
lut[bytes[1]] +
lut[bytes[2]] +
lut[bytes[3]] +
'-' +
lut[bytes[4]] +
lut[bytes[5]] +
'-' +
lut[bytes[6]] +
lut[bytes[7]] +
'-' +
lut[bytes[8]] +
lut[bytes[9]] +
'-' +
lut[bytes[10]] +
lut[bytes[11]] +
lut[bytes[12]] +
lut[bytes[13]] +
lut[bytes[14]] +
lut[bytes[15]]);
};
}
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* The namespace for UUID related functionality.
*/
var UUID;
(function (UUID) {
/**
* A function which generates UUID v4 identifiers.
*
* @returns A new UUID v4 string.
*
* #### Notes
* This implementation complies with RFC 4122.
*
* This uses `Random.getRandomValues()` for random bytes, which in
* turn will use the underlying `crypto` module of the platform if
* it is available. The fallback for randomness is `Math.random`.
*/
UUID.uuid4 = uuid4Factory(Random.getRandomValues);
})(UUID || (UUID = {}));
export { JSONExt, MimeData, PluginRegistry, PromiseDelegate, Random, Token, UUID };
//# sourceMappingURL=index.node.es6.js.map