module.exports should default to an empty object.

Per the spec in modules.md the exports property should default to an
empty object. We lazy allocate it so that modules that just replace it
don't create the empty object and then throw it away.

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/872043003
This commit is contained in:
Elliott Sprehn 2015-01-26 11:38:04 -08:00
parent 44686c5f02
commit 30c38af903
11 changed files with 39 additions and 16 deletions

View File

@ -295,7 +295,7 @@ void ScriptController::executeModuleScript(AbstractModule& module, const String&
scriptModule.formalDependencies.append(name);
v8::Handle<v8::Value> actual;
if (Module* childModule = child->module())
actual = childModule->exports().v8Value();
actual = childModule->exports(scriptState).v8Value();
if (actual.IsEmpty())
actual = v8::Undefined(m_isolate);
scriptModule.resolvedDependencies.append(actual);

View File

@ -60,6 +60,11 @@ public:
ASSERT(isEmpty() || m_scriptState);
}
static ScriptValue createEmptyObject(ScriptState* scriptState)
{
return ScriptValue(scriptState, v8::Object::New(scriptState->isolate()));
}
ScriptState* scriptState() const
{
return m_scriptState.get();

View File

@ -249,6 +249,9 @@ v8::Local<v8::Value> v8Value, const v8::PropertyCallbackInfo<void>& info
attribute.is_setter_call_with_execution_context %}
ExecutionContext* executionContext = currentExecutionContext(info.GetIsolate());
{% endif %}
{% if attribute.is_call_with_script_state %}
ScriptState* scriptState = ScriptState::current(info.GetIsolate());
{% endif %}
{# Set #}
{{attribute.cpp_setter}};
{# Post-set #}

View File

@ -41,7 +41,7 @@ void AbstractModule::OnModuleLoadComplete(ModuleLoader* loader,
Module* module) {
RefPtr<ScriptPromiseResolver> resolver = loaders_.take(loader);
ScriptState::Scope scope(resolver->scriptState());
resolver->resolve(module->exports().v8Value());
resolver->resolve(module->exports(resolver->scriptState()).v8Value());
}
} // namespace blink

View File

@ -29,4 +29,14 @@ Application* Module::GetApplication() {
return application();
}
void Module::setExports(ScriptState*, const ScriptValue& exports) {
exports_ = exports;
}
const ScriptValue& Module::exports(ScriptState* scriptState) const {
if (exports_.isEmpty())
exports_ = ScriptValue::createEmptyObject(scriptState);
return exports_;
}
} // namespace blink

View File

@ -24,8 +24,8 @@ public:
Application* application() const { return application_.get(); }
void setExports(const ScriptValue& exports) { exports_ = exports; }
const ScriptValue& exports() const { return exports_; }
void setExports(ScriptState*, const ScriptValue& exports);
const ScriptValue& exports(ScriptState*) const;
private:
Module(ExecutionContext* context,
@ -37,7 +37,7 @@ private:
Application* GetApplication() override;
RefPtr<Application> application_;
ScriptValue exports_;
mutable ScriptValue exports_;
};
} // namespace blink

View File

@ -7,5 +7,5 @@
Constructor(Application application, Document document, DOMString url),
] interface Module : AbstractModule {
readonly attribute Application application;
attribute any exports;
[CallWith=ScriptState] attribute any exports;
};

View File

@ -7,11 +7,6 @@
<import src="city-data-service.sky" as="CityDataService" />
<import src="city-sequence.sky" as="CitySequence" />
<script>
// TODO(esprehn): exports should start as the empty object.
module.exports = {};
</script>
<sky-element name="state-header">
<template>
<style>

View File

@ -3,7 +3,9 @@
<import src="../resources/dump-as-text.sky" />
<div id="result">FAIL - Script did not execute</div>
<script>
document.getElementById("result").textContent =
hello === undefined ? "PASS" : "FAIL";
var result = "FAIL";
if (typeof hello === "object" && Object.keys(hello).length === 0)
result = "PASS";
document.getElementById("result").textContent = result;
</script>
</html>

View File

@ -1,5 +1,6 @@
Running 1 tests
Running 2 tests
ok 1 Module should be constructable
1 tests
1 pass
ok 2 Module should have an empty object by default for exports
2 tests
2 pass
0 fail

View File

@ -13,6 +13,13 @@ describe('Module', function() {
assert.equal(module.document, doc2);
assert.equal(module.url, "http://www.example.com/module");
});
it('should have an empty object by default for exports', function() {
var app = new Application(new Document(), "http://www.example.com/app");
var module = new Module(app, new Document(), "http://www.example.com/module");
assert.isObject(module.exports);
assert.lengthOf(Object.keys(module.exports), 0);
});
});
</script>
</html>