Browse Source

intl: Add more versions from ICU

* Adds process.versions.cldr, .tz, and .unicode
* Changes how process.versions.icu is loaded
* Lazy loads the process.versions.* values for these
* add an exception to util.js
   to cause 'node -p process.versions' to still work
* update process.version docs

Fixes: https://github.com/nodejs/node/issues/9237
v6
Steven R. Loomis 8 years ago
parent
commit
4fb27d43f0
No known key found for this signature in database GPG Key ID: 3932080F4FB419E3
  1. 6
      doc/api/process.md
  2. 32
      lib/internal/bootstrap_node.js
  3. 4
      lib/util.js
  4. 4
      src/node.cc
  5. 68
      src/node_i18n.cc
  6. 3
      test/parallel/test-process-versions.js

6
doc/api/process.md

@ -1643,8 +1643,10 @@ Will generate output similar to:
ares: '1.10.0-DEV', ares: '1.10.0-DEV',
modules: '43', modules: '43',
icu: '55.1', icu: '55.1',
openssl: '1.0.1k' openssl: '1.0.1k',
} unicode: '8.0',
cldr: '29.0',
tz: '2016b' }
``` ```
## Exit Codes ## Exit Codes

32
lib/internal/bootstrap_node.js

@ -26,6 +26,8 @@
// do this good and early, since it handles errors. // do this good and early, since it handles errors.
setupProcessFatal(); setupProcessFatal();
setupProcessICUVersions();
setupGlobalVariables(); setupGlobalVariables();
if (!process._noBrowserGlobals) { if (!process._noBrowserGlobals) {
setupGlobalTimeouts(); setupGlobalTimeouts();
@ -304,6 +306,36 @@
}; };
} }
function setupProcessICUVersions() {
const icu = process.binding('config').hasIntl ?
process.binding('icu') : undefined;
if (!icu) return; // no Intl/ICU: nothing to add here.
// With no argument, getVersion() returns a comma separated list
// of possible types.
const versionTypes = icu.getVersion().split(',');
versionTypes.forEach((name) => {
// Copied from module.js:addBuiltinLibsToObject
Object.defineProperty(process.versions, name, {
configurable: true,
enumerable: true,
get: () => {
// With an argument, getVersion(type) returns
// the actual version string.
const version = icu.getVersion(name);
// Replace the current getter with a new
// property.
delete process.versions[name];
Object.defineProperty(process.versions, name, {
value: version,
writable: false,
enumerable: true
});
return version;
}
});
});
}
function tryGetCwd(path) { function tryGetCwd(path) {
var threw = true; var threw = true;
var cwd; var cwd;

4
lib/util.js

@ -1049,3 +1049,7 @@ exports._exceptionWithHostPort = function(err,
} }
return ex; return ex;
}; };
// process.versions needs a custom function as some values are lazy-evaluated.
process.versions[exports.inspect.custom] =
(depth) => exports.format(JSON.parse(JSON.stringify(process.versions)));

4
src/node.cc

@ -3032,9 +3032,7 @@ void SetupProcessObject(Environment* env,
FIXED_ONE_BYTE_STRING(env->isolate(), ARES_VERSION_STR)); FIXED_ONE_BYTE_STRING(env->isolate(), ARES_VERSION_STR));
#if defined(NODE_HAVE_I18N_SUPPORT) && defined(U_ICU_VERSION) #if defined(NODE_HAVE_I18N_SUPPORT) && defined(U_ICU_VERSION)
READONLY_PROPERTY(versions, // ICU-related versions are now handled on the js side, see bootstrap_node.js
"icu",
OneByteString(env->isolate(), U_ICU_VERSION));
if (icu_data_dir != nullptr) { if (icu_data_dir != nullptr) {
// Did the user attempt (via env var or parameter) to set an ICU path? // Did the user attempt (via env var or parameter) to set an ICU path?

68
src/node_i18n.cc

@ -31,14 +31,18 @@
#include "util-inl.h" #include "util-inl.h"
#include "v8.h" #include "v8.h"
#include <unicode/utypes.h>
#include <unicode/putil.h> #include <unicode/putil.h>
#include <unicode/uchar.h> #include <unicode/uchar.h>
#include <unicode/udata.h> #include <unicode/udata.h>
#include <unicode/uidna.h> #include <unicode/uidna.h>
#include <unicode/utypes.h>
#include <unicode/ucnv.h> #include <unicode/ucnv.h>
#include <unicode/utf8.h> #include <unicode/utf8.h>
#include <unicode/utf16.h> #include <unicode/utf16.h>
#include <unicode/timezone.h>
#include <unicode/ulocdata.h>
#include <unicode/uvernum.h>
#include <unicode/uversion.h>
#ifdef NODE_HAVE_SMALL_ICU #ifdef NODE_HAVE_SMALL_ICU
/* if this is defined, we have a 'secondary' entry point. /* if this is defined, we have a 'secondary' entry point.
@ -339,6 +343,67 @@ static void ICUErrorName(const FunctionCallbackInfo<Value>& args) {
v8::NewStringType::kNormal).ToLocalChecked()); v8::NewStringType::kNormal).ToLocalChecked());
} }
#define TYPE_ICU "icu"
#define TYPE_UNICODE "unicode"
#define TYPE_CLDR "cldr"
#define TYPE_TZ "tz"
/**
* This is the workhorse function that deals with the actual version info.
* Get an ICU version.
* @param type the type of version to get. One of VERSION_TYPES
* @param buf optional buffer for result
* @param status ICU error status. If failure, assume result is undefined.
* @return version number, or NULL. May or may not be buf.
*/
static const char* GetVersion(const char* type,
char buf[U_MAX_VERSION_STRING_LENGTH],
UErrorCode* status) {
if (!strcmp(type, TYPE_ICU)) {
return U_ICU_VERSION;
} else if (!strcmp(type, TYPE_UNICODE)) {
return U_UNICODE_VERSION;
} else if (!strcmp(type, TYPE_TZ)) {
return TimeZone::getTZDataVersion(*status);
} else if (!strcmp(type, TYPE_CLDR)) {
UVersionInfo versionArray;
ulocdata_getCLDRVersion(versionArray, status);
if (U_SUCCESS(*status)) {
u_versionToString(versionArray, buf);
return buf;
}
}
// Fall through - unknown type or error case
return nullptr;
}
static void GetVersion(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
if ( args.Length() == 0 ) {
// With no args - return a comma-separated list of allowed values
args.GetReturnValue().Set(
String::NewFromUtf8(env->isolate(),
TYPE_ICU ","
TYPE_UNICODE ","
TYPE_CLDR ","
TYPE_TZ));
} else {
CHECK_GE(args.Length(), 1);
CHECK(args[0]->IsString());
Utf8Value val(env->isolate(), args[0]);
UErrorCode status = U_ZERO_ERROR;
char buf[U_MAX_VERSION_STRING_LENGTH] = ""; // Possible output buffer.
const char* versionString = GetVersion(*val, buf, &status);
if (U_SUCCESS(status) && versionString) {
// Success.
args.GetReturnValue().Set(
String::NewFromUtf8(env->isolate(),
versionString));
}
}
}
bool InitializeICUDirectory(const char* icu_data_path) { bool InitializeICUDirectory(const char* icu_data_path) {
if (icu_data_path != nullptr) { if (icu_data_path != nullptr) {
flag_icu_data_dir = true; flag_icu_data_dir = true;
@ -558,6 +623,7 @@ void Init(Local<Object> target,
env->SetMethod(target, "toUnicode", ToUnicode); env->SetMethod(target, "toUnicode", ToUnicode);
env->SetMethod(target, "toASCII", ToASCII); env->SetMethod(target, "toASCII", ToASCII);
env->SetMethod(target, "getStringWidth", GetStringWidth); env->SetMethod(target, "getStringWidth", GetStringWidth);
env->SetMethod(target, "getVersion", GetVersion);
// One-shot converters // One-shot converters
env->SetMethod(target, "icuErrName", ICUErrorName); env->SetMethod(target, "icuErrName", ICUErrorName);

3
test/parallel/test-process-versions.js

@ -11,6 +11,9 @@ if (common.hasCrypto) {
if (common.hasIntl) { if (common.hasIntl) {
expected_keys.push('icu'); expected_keys.push('icu');
expected_keys.push('cldr');
expected_keys.push('tz');
expected_keys.push('unicode');
} }
expected_keys.sort(); expected_keys.sort();

Loading…
Cancel
Save