time-to-botec/squiggle/node_modules/@stdlib/string/from-code-point/lib/main.js

116 lines
3.5 KiB
JavaScript
Raw Normal View History

/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
// MODULES //
var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
var isCollection = require( '@stdlib/assert/is-collection' );
var format = require( './../../format' );
var UNICODE_MAX = require( '@stdlib/constants/unicode/max' );
var UNICODE_MAX_BMP = require( '@stdlib/constants/unicode/max-bmp' );
// VARIABLES //
var fromCharCode = String.fromCharCode;
// Factor to rescale a code point from a supplementary plane:
var Ox10000 = 0x10000|0; // 65536
// Factor added to obtain a high surrogate:
var OxD800 = 0xD800|0; // 55296
// Factor added to obtain a low surrogate:
var OxDC00 = 0xDC00|0; // 56320
// 10-bit mask: 2^10-1 = 1023 => 0x3ff => 00000000 00000000 00000011 11111111
var Ox3FF = 1023|0;
// MAIN //
/**
* Creates a string from a sequence of Unicode code points.
*
* ## Notes
*
* - UTF-16 encoding uses one 16-bit unit for non-surrogates (U+0000 to U+D7FF and U+E000 to U+FFFF).
* - UTF-16 encoding uses two 16-bit units (surrogate pairs) for U+10000 to U+10FFFF and encodes U+10000-U+10FFFF by subtracting 0x10000 from the code point, expressing the result as a 20-bit binary, and splitting the 20 bits of 0x0-0xFFFFF as upper and lower 10-bits. The respective 10-bits are stored in two 16-bit words: a high and a low surrogate.
*
*
* @param {...NonNegativeInteger} args - sequence of code points
* @throws {Error} must provide either an array-like object of code points or one or more code points as separate arguments
* @throws {TypeError} a code point must be a nonnegative integer
* @throws {RangeError} must provide a valid Unicode code point
* @returns {string} created string
*
* @example
* var str = fromCodePoint( 9731 );
* // returns '☃'
*/
function fromCodePoint( args ) {
var len;
var str;
var arr;
var low;
var hi;
var pt;
var i;
len = arguments.length;
if ( len === 1 && isCollection( args ) ) {
arr = arguments[ 0 ];
len = arr.length;
} else {
arr = [];
for ( i = 0; i < len; i++ ) {
arr.push( arguments[ i ] );
}
}
if ( len === 0 ) {
throw new Error( 'insufficient arguments. Must provide either an array of code points or one or more code points as separate arguments.' );
}
str = '';
for ( i = 0; i < len; i++ ) {
pt = arr[ i ];
if ( !isNonNegativeInteger( pt ) ) {
throw new TypeError( format( 'invalid argument. Must provide valid code points (i.e., nonnegative integers). Value: `%s`.', pt ) );
}
if ( pt > UNICODE_MAX ) {
throw new RangeError( format( 'invalid argument. Must provide a valid code point (i.e., cannot exceed %u). Value: `%s`.', UNICODE_MAX, pt ) );
}
if ( pt <= UNICODE_MAX_BMP ) {
str += fromCharCode( pt );
} else {
// Code point from a supplementary plane. Split into two 16-bit code units (surrogate pair).
pt -= Ox10000;
hi = (pt >> 10) + OxD800;
low = (pt & Ox3FF) + OxDC00;
str += fromCharCode( hi, low );
}
}
return str;
}
// EXPORTS //
module.exports = fromCodePoint;