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; }
bool V8HiddenValue::deleteHiddenValue(v8::Isolate* isolate, v8::Local<v8::Object> object, v8::Local<v8::String> key) { return object->DeleteHiddenValue(key); }