result_t doDefine(v8::Local<v8::Object> &mod) { v8::Local<v8::Array> defs; { v8::Local<v8::Value> v; v8::Local<v8::String> strDefs = v8::String::NewFromUtf8(isolate, "defs"); // get define array from default module v = mod->GetHiddenValue(strDefs); mod->DeleteHiddenValue(strDefs); if (!v.IsEmpty() && v->IsArray()) defs = v8::Local<v8::Array>::Cast(v); else return 0; } int an = defs->Length(), i, j; std::vector<v8::Local<v8::Object> > mods; std::vector<std::string> modIds; std::set<std::string> depns; // cache string v8::Local<v8::String> strRequire = v8::String::NewFromUtf8(isolate, "require"); v8::Local<v8::String> strExports = v8::String::NewFromUtf8(isolate, "exports"); v8::Local<v8::String> strDeps = v8::String::NewFromUtf8(isolate, "deps"); v8::Local<v8::String> strFactory = v8::String::NewFromUtf8(isolate, "factory"); v8::Local<v8::String> strId = v8::String::NewFromUtf8(isolate, "id"); // copy data to local mods.resize(an); modIds.resize(an); for (i = 0; i < an; i++) { mods[i] = defs->Get(i)->ToObject(); modIds[i] = *v8::String::Utf8Value(mods[i]->Get(strId)); depns.insert(modIds[i]); } // two step int doStep = 2; bool bNext = false; while (doStep) { bNext = true; for (i = 0; i < an; i++) { if (!modIds[i].empty()) { // get deps array v8::Local<v8::Value> a1 = mods[i]->GetHiddenValue(strDeps); if (a1.IsEmpty() || !a1->IsArray()) { // not found deps array depns.erase(modIds[i]); modIds[i].clear(); bNext = false; continue; } v8::Local<v8::Array> a = v8::Local<v8::Array>::Cast(a1); int n = a->Length(); // check if the module depend a module defined in same script for (j = 0; j < n; j++) if (doStep == 2 && depns.find(*v8::String::Utf8Value(a->Get(j))) != depns.end()) break; if (j == n) { std::vector<v8::Local<v8::Value> > deps; deps.resize(n); for (j = 0; j < n; j++) { v8::String::Utf8Value id(a->Get(j)); if (!qstrcmp(*id, "require")) deps[j] = mods[i]->Get(strRequire); else if (!qstrcmp(*id, "exports")) deps[j] = mods[i]->Get(strExports); else if (!qstrcmp(*id, "module")) deps[j] = mods[i]; else { // load module use require result_t hr = global_base::require(*id, deps[j]); if (hr < 0) return hr; } } v8::Local<v8::Value> v; // get factory and remove hidden value. v = mods[i]->GetHiddenValue(strFactory); mods[i]->DeleteHiddenValue(strFactory); mods[i]->DeleteHiddenValue(strDeps); if (v->IsFunction()) { v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(v); v = func->Call(func, n, deps.data()); if (v.IsEmpty()) return CALL_E_JAVASCRIPT; } // use the result as exports if the factory return something if (!IsEmpty(v)) mods[i]->Set(strExports, v); else v = mods[i]->Get(strExports); InstallModule(modIds[i], v); // remove id name, we don't like to call it again depns.erase(modIds[i]); modIds[i].clear(); bNext = false; } } } if (bNext) doStep--; } return 0; }
std::string json_format(v8::Local<v8::Value> obj) { StringBuffer strBuffer; Isolate* isolate = Isolate::current(); QuickArray<_item> stk; QuickArray<v8::Local<v8::Object>> vals; v8::Local<v8::Value> v = obj; v8::Local<v8::String> mark_name = isolate->NewFromUtf8("_util_format_mark"); int32_t padding = 0; const int32_t tab_size = 2; _item *it = NULL; while (true) { if (v.IsEmpty()) strBuffer.append("undefined"); else if (v->IsUndefined() || v->IsNull() || v->IsDate() || v->IsBoolean() || v->IsBooleanObject()) strBuffer.append(*v8::String::Utf8Value(v)); else if (v->IsNumber() || v->IsNumberObject()) strBuffer.append(*v8::String::Utf8Value(v->ToNumber())); else if (v->IsString() || v->IsStringObject()) string_format(strBuffer, v); else if (v->IsRegExp()) { v8::Local<v8::RegExp> re = v8::Local<v8::RegExp>::Cast(v); v8::Local<v8::String> src = re->GetSource(); v8::RegExp::Flags flgs = re->GetFlags(); strBuffer.append('/'); strBuffer.append(*v8::String::Utf8Value(src)); strBuffer.append('/'); if (flgs & v8::RegExp::kIgnoreCase) strBuffer.append('i'); if (flgs & v8::RegExp::kGlobal) strBuffer.append('g'); if (flgs & v8::RegExp::kMultiline) strBuffer.append('m'); } else if (v->IsObject()) { do { v8::Local<v8::Object> obj = v->ToObject(); v8::Local<v8::Array> keys = obj->GetPropertyNames(); if (v->IsFunction() && keys->Length() == 0) { strBuffer.append("[Function]"); break; } obj_ptr<Buffer_base> buf = Buffer_base::getInstance(v); if (buf) { static char hexs[] = "0123456789abcdef"; std::string data; std::string s; int32_t len, i; buf->toString(data); len = (int32_t)data.length(); s.resize(len * 3 + 8); memcpy(&s[0], "<Buffer", 7); for (i = 0; i < len; i ++) { int32_t ch = (unsigned char)data[i]; s[i * 3 + 7] = ' '; s[i * 3 + 8] = hexs[ch >> 4]; s[i * 3 + 9] = hexs[ch & 0xf]; } s[i * 3 + 7] = '>'; strBuffer.append(s); break; } obj_ptr<Int64_base> int64Val = Int64_base::getInstance(v); if (int64Val) { std::string s; int64Val->toString(10, s); strBuffer.append(s); break; } v8::Local<v8::Value> mk = obj->GetHiddenValue(mark_name); if (!mk.IsEmpty()) { strBuffer.append("[Circular]"); break; } vals.append(obj); obj->SetHiddenValue(mark_name, obj); v8::Local<v8::Value> toArray = obj->Get(isolate->NewFromUtf8("toArray")); if (!IsEmpty(toArray) && toArray->IsFunction()) { v = v8::Local<v8::Function>::Cast(toArray)->Call(obj, 0, NULL); obj = v->ToObject(); } int32_t sz = (int32_t)stk.size(); if (v->IsArray()) { v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(v); int32_t len = array->Length(); if (len == 0) strBuffer.append("[]"); else { if (len == 1 && v->StrictEquals(array->Get(0))) strBuffer.append("[Circular]"); else { stk.resize(sz + 1); it = &stk[sz]; it->val = v; it->keys = array; it->len = len; strBuffer.append('['); padding += tab_size; } } break; } int32_t len = keys->Length(); if (len == 0) strBuffer.append("{}"); else { if (len == 1 && v->StrictEquals(obj->Get(keys->Get(0)))) strBuffer.append("[Circular]"); else { stk.resize(sz + 1); it = &stk[sz]; it->val = v; it->obj = obj; it->keys = keys; it->len = len; strBuffer.append('{'); padding += tab_size; } } } while (false); } if (it) { while (it && it->pos == it->len) { padding -= tab_size; newline(strBuffer, padding); strBuffer.append(it->obj.IsEmpty() ? ']' : '}'); int32_t sz = (int32_t)stk.size(); stk.resize(sz - 1); if (sz > 1) it = &stk[sz - 2]; else it = NULL; } if (!it) break; if (it->pos) strBuffer.append(','); newline(strBuffer, padding); v = it->keys->Get(it->pos ++); if (!it->obj.IsEmpty()) { TryCatch try_catch; string_format(strBuffer, v); strBuffer.append(": "); v = it->obj->Get(v); } } else break; } int32_t sz1 = (int32_t)vals.size(); int32_t i; for (i = 0; i < sz1; i ++) vals[i]->DeleteHiddenValue(mark_name); return strBuffer.str(); }
v8::Local<v8::Value> V8HiddenValue::getHiddenValue(v8::Isolate* isolate, v8::Local<v8::Object> object, v8::Local<v8::String> key) { return object->GetHiddenValue(key); }