[gjs/wip/require: 10/11] bootstrap: Add a CommonJS-style imports system



commit ef047126ead6702696f2eb14492b0a5325d690af
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Thu Jan 2 15:59:16 2014 -0500

    bootstrap: Add a CommonJS-style imports system
    
    Use a native JS hook to add an implementation of the CommonJS Modules
    1.1.1 specification, using require(). This is independent from the
    existing imports system.
    
    This implementation has one minor deviation from the spec to be more
    compatible with the old imports system, and that is that modules are
    not run in their own private namespace, but instead directly in their
    "exports" namespace. That is, "this" and "exports" are the same object
    within the module. The "module" variable is also on "exports".
    This means that we can port the majority of modules over without
    requiring that they be rewritten to use exports, which doesn't exist
    in old versions of gjs.
    
    The existing imports system is considered deprecated, and will soon
    be rewritten as a compatibility layer in JS.

 Makefile-modules.am          |    6 ++-
 doc/Style_Guide.txt          |   12 ++--
 doc/cairo.txt                |    2 +-
 examples/clutter.js          |    3 +-
 examples/gettext.js          |    4 +-
 examples/gio-cat.js          |    4 +-
 examples/gtk.js              |    3 +-
 examples/http-server.js      |    2 +-
 examples/webkit.js           |    5 +-
 gjs/bootstrap.cpp            |   42 ++++++++++++
 gjs/console.cpp              |    2 +-
 gjs/context.cpp              |    6 ++
 gjs/context.h                |    2 +
 gjs/importer.cpp             |    2 +-
 gjs/importer.h               |    2 +
 libgjs-private/gjs-util.h    |    4 +-
 modules/bootstrap.js         |  137 ++++++++++++++++++++++++++++++++++++-
 modules/cairo.js             |    5 +-
 modules/format.js            |    2 +-
 modules/gettext.js           |    6 +-
 modules/importer.cpp         |  153 ++++++++++++++++++++++++++++++++++++++++++
 modules/importer.h           |   38 ++++++++++
 modules/lang.js              |    2 +-
 modules/mainloop.js          |    4 +-
 modules/modules.cpp          |    2 +
 modules/overrides/GLib.js    |    6 +-
 modules/overrides/GObject.js |    4 +-
 modules/overrides/Gio.js     |   10 ++--
 modules/tweener/tweener.js   |   11 ++--
 29 files changed, 432 insertions(+), 49 deletions(-)
---
diff --git a/Makefile-modules.am b/Makefile-modules.am
index ef922a9..eafd706 100644
--- a/Makefile-modules.am
+++ b/Makefile-modules.am
@@ -1,5 +1,5 @@
 
-NATIVE_MODULES = libconsole.la libsystem.la libmodules_resources.la
+NATIVE_MODULES = libconsole.la libsystem.la libmodules_resources.la libimporter.la
 if ENABLE_CAIRO
 NATIVE_MODULES += libcairoNative.la
 endif
@@ -61,3 +61,7 @@ libsystem_la_SOURCES = modules/system.h modules/system.cpp
 libconsole_la_CPPFLAGS = $(JS_NATIVE_MODULE_CFLAGS)
 libconsole_la_LIBADD = $(JS_NATIVE_MODULE_LIBADD) $(READLINE_LIBS)
 libconsole_la_SOURCES = modules/console.h modules/console.cpp
+
+libimporter_la_CPPFLAGS = $(JS_NATIVE_MODULE_CFLAGS)
+libimporter_la_LIBADD = $(JS_NATIVE_MODULE_LIBADD)
+libimporter_la_SOURCES = modules/importer.h modules/importer.cpp
diff --git a/doc/Style_Guide.txt b/doc/Style_Guide.txt
index e93a601..eb7e700 100644
--- a/doc/Style_Guide.txt
+++ b/doc/Style_Guide.txt
@@ -19,8 +19,8 @@ and the like.
 Use CamelCase when importing modules to distinguish them from ordinary variables, e.g.
 
 <pre>
-const Big = imports.big;
-const GLib = imports.gi.GLib;
+const Big = require('big');
+const GLib = require('gi/GLib');
 </pre>
 
 
@@ -62,7 +62,7 @@ in at function invocation time, it is not a variable that can be captured in clo
 To solve this, use Lang.bind, eg:
 
 <pre>
-const Lang = imports.lang;
+const Lang = require('lang');
 
 let closure = Lang.bind(this, function() { this._fnorbate() });
 </pre>
@@ -71,7 +71,7 @@ A more realistic example would be connecting to a signal on a
 method of a prototype:
 
 <pre>
-const Lang = imports.lang;
+const Lang = require('lang');
 
 MyPrototype = {
     _init : function() {
@@ -106,7 +106,7 @@ If your usage of an object is like a hash table (and thus conceptually the keys
 # We use javaStyle variable names, with CamelCase for type names and lowerCamelCase for variable and method 
names. However, when calling a C method with underscore-based names via introspection, we just keep them 
looking as they do in C for simplicity.
 # Private variables, whether object member variables or module-scoped variables, should begin with "_".
 # True global variables (in the global or 'window' object) should be avoided whenever possible. If you do 
create them, the variable name should have a namespace in it, like "BigFoo"
-# When you assign a module to an alias to avoid typing "imports.foo.bar" all the time, the alias should be 
"const TitleCase" so "const Bar = imports.foo.bar;"
+# When you assign a module to an alias to avoid typing "require('foo/bar')" all the time, the alias should 
be "const TitleCase" so "const Bar = require('foo/bar');"
 # If you need to name a variable something weird to avoid a namespace collision, add a trailing "_" (not 
leading, leading "_" means private).
 # For GObject constructors, always use the lowerCamelCase style for property names instead of dashes or 
underscores.
 
@@ -170,7 +170,7 @@ There are lots of ways to simulate "inheritance" in JavaScript. In general, it's
 
 Our preferred approach is to use a Spidermonkey-specific extension and directly set the __proto__ member of 
the subclass's prototype to point to the prototype of the base class. Looking up a property in the subclass 
starts with the properties of the instance. If the property isn't there, then the prototype chain is followed 
first to the subclass's prototype and then to the base class's prototype.
 <pre>
-const Lang = imports.lang;
+const Lang = require('lang');
 
 function Base(foo) {
   this._init(foo);
diff --git a/doc/cairo.txt b/doc/cairo.txt
index 17b1152..e4071a5 100644
--- a/doc/cairo.txt
+++ b/doc/cairo.txt
@@ -6,7 +6,7 @@ Naming
 The module name is called 'cairo' and usually imported into
 the namespace as 'Cairo'.
 
-gjs> const Cairo = imports.cairo;
+gjs> const Cairo = require('cairo');
 
 Methods are studlyCaps, similar to other JavaScript apis, eg
 
diff --git a/examples/clutter.js b/examples/clutter.js
index a6b50ed..f0872f9 100644
--- a/examples/clutter.js
+++ b/examples/clutter.js
@@ -1,4 +1,5 @@
-const Clutter = imports.gi.Clutter;
+
+const Clutter = require('gi/Clutter');
 
 Clutter.init(null);
 
diff --git a/examples/gettext.js b/examples/gettext.js
index 44377fc..78f3364 100644
--- a/examples/gettext.js
+++ b/examples/gettext.js
@@ -1,6 +1,6 @@
 
-const Gettext = imports.gettext;
-const Gtk = imports.gi.Gtk;
+const Gettext = require('gettext');
+const Gtk = require('gi/Gtk');
 
 Gettext.bindtextdomain("gnome-panel-3.0", "/usr/share/locale");
 Gettext.textdomain("gnome-panel-3.0");
diff --git a/examples/gio-cat.js b/examples/gio-cat.js
index f26e710..842769b 100644
--- a/examples/gio-cat.js
+++ b/examples/gio-cat.js
@@ -1,6 +1,6 @@
 
-const GLib = imports.gi.GLib;
-const Gio = imports.gi.Gio;
+const GLib = require('gi/GLib');
+const Gio = require('gi/Gio');
 
 let loop = GLib.MainLoop.new(null, false);
 
diff --git a/examples/gtk.js b/examples/gtk.js
index 638a147..c44f460 100644
--- a/examples/gtk.js
+++ b/examples/gtk.js
@@ -1,4 +1,5 @@
-const Gtk = imports.gi.Gtk;
+
+const Gtk = require('gi/Gtk');
 
 // This is a callback function. The data arguments are ignored
 // in this example. More on callbacks below.
diff --git a/examples/http-server.js b/examples/http-server.js
index 36c73f0..d7910fa 100644
--- a/examples/http-server.js
+++ b/examples/http-server.js
@@ -1,6 +1,6 @@
 // This is a simple example of a HTTP server in Gjs using libsoup
 
-const Soup = imports.gi.Soup;
+const Soup = require('gi/Soup');
 
 function main() {
     let handler = function(server, msg, path, query, client) {
diff --git a/examples/webkit.js b/examples/webkit.js
index 064cef6..8427370 100644
--- a/examples/webkit.js
+++ b/examples/webkit.js
@@ -1,5 +1,6 @@
-const Gtk = imports.gi.Gtk;
-const WebKit = imports.gi.WebKit;
+
+const Gtk = require('gi/Gtk');
+const WebKit = require('gi/WebKit');
 
 Gtk.init(null);
 
diff --git a/gjs/bootstrap.cpp b/gjs/bootstrap.cpp
index b049ec4..406c26f 100644
--- a/gjs/bootstrap.cpp
+++ b/gjs/bootstrap.cpp
@@ -26,9 +26,48 @@
 #include <gjs/gjs.h>
 
 #include "bootstrap.h"
+#include "native.h"
 
 #include <gio/gio.h>
 
+/* The bootstrap process is the thing that sets up the import system.
+ * As such, we give it a hook to import any native modules it may need.
+ *
+ * The rest of the functionality that the bootstrap code needs should be
+ * in independent native modules which can be imported by this API,
+ * rather than in the bootstrap environment.
+ */
+
+static JSBool
+import_native_module(JSContext *context,
+                     unsigned   argc,
+                     jsval     *vp)
+{
+    JSBool ret = JS_FALSE;
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    char *module_name = NULL;
+    JSObject *module_obj;
+
+    if (!gjs_parse_call_args(context, "importNativeModule", "s", args,
+                             "moduleName", &module_name))
+        goto out;
+
+    if (!gjs_import_native_module(context, module_name, &module_obj))
+        goto out;
+
+    ret = JS_TRUE;
+    args.rval().setObjectOrNull(module_obj);
+
+ out:
+    g_free(module_name);
+    return ret;
+}
+
+static JSFunctionSpec environment_funcs[] = {
+    { "importNativeModule", JSOP_WRAPPER (import_native_module), 1, GJS_MODULE_PROP_FLAGS },
+    { NULL },
+};
+
 static gboolean
 define_bootstrap_environment(JSContext  *context,
                              JSObject  **environment_out)
@@ -38,6 +77,9 @@ define_bootstrap_environment(JSContext  *context,
     if (!environment)
         return FALSE;
 
+    if (!JS_DefineFunctions(context, environment, &environment_funcs[0]))
+        return FALSE;
+
     *environment_out = environment;
     return TRUE;
 }
diff --git a/gjs/console.cpp b/gjs/console.cpp
index d96bd45..6cb4caf 100644
--- a/gjs/console.cpp
+++ b/gjs/console.cpp
@@ -90,7 +90,7 @@ main(int argc, char **argv)
         filename = "<command line>";
         program_name = argv[0];
     } else if (argc <= 1) {
-        script = g_strdup("const Console = imports.console; Console.interact();");
+        script = g_strdup("const Console = require('console'); Console.interact();");
         len = strlen(script);
         filename = "<stdin>";
         program_name = argv[0];
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 77fa6d1..46f3302 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -759,3 +759,9 @@ gjs_object_get_property_const(JSContext      *context,
     pname = gjs_context_get_const_string(context, property_name);
     return JS_GetPropertyById(context, obj, pname, value_p);
 }
+
+const char **
+gjs_context_get_search_path(GjsContext *context)
+{
+    return (const char **) context->search_path;
+}
diff --git a/gjs/context.h b/gjs/context.h
index ccd8bc6..acd07d1 100644
--- a/gjs/context.h
+++ b/gjs/context.h
@@ -77,6 +77,8 @@ void            gjs_context_gc                    (GjsContext  *context);
 
 void            gjs_dumpstack                     (void);
 
+const char **   gjs_context_get_search_path       (GjsContext *context);
+
 G_END_DECLS
 
 #endif  /* __GJS_CONTEXT_H__ */
diff --git a/gjs/importer.cpp b/gjs/importer.cpp
index a76986f..94d5aec 100644
--- a/gjs/importer.cpp
+++ b/gjs/importer.cpp
@@ -1006,7 +1006,7 @@ importer_new(JSContext *context,
     return importer;
 }
 
-static G_CONST_RETURN char * G_CONST_RETURN *
+G_CONST_RETURN char * G_CONST_RETURN *
 gjs_get_search_path(void)
 {
     char **search_path;
diff --git a/gjs/importer.h b/gjs/importer.h
index afd4ab1..8f11fb8 100644
--- a/gjs/importer.h
+++ b/gjs/importer.h
@@ -29,6 +29,7 @@
 #endif
 
 #include <glib.h>
+#include <gio/gio.h>
 #include "gjs/jsapi-util.h"
 
 G_BEGIN_DECLS
@@ -44,6 +45,7 @@ JSObject* gjs_define_importer      (JSContext   *context,
                                     const char **initial_search_path,
                                     gboolean     add_standard_search_path);
 
+G_CONST_RETURN char * G_CONST_RETURN * gjs_get_search_path (void);
 
 G_END_DECLS
 
diff --git a/libgjs-private/gjs-util.h b/libgjs-private/gjs-util.h
index 0eb55f6..95c79d0 100644
--- a/libgjs-private/gjs-util.h
+++ b/libgjs-private/gjs-util.h
@@ -27,10 +27,10 @@
 
 G_BEGIN_DECLS
 
-/* For imports.format */
+/* For 'format' */
 char * gjs_format_int_alternative_output (int n);
 
-/* For imports.gettext */
+/* For 'gettext' */
 void gjs_textdomain     (const char *domain);
 void gjs_bindtextdomain (const char *domain,
                          const char *location);
diff --git a/modules/bootstrap.js b/modules/bootstrap.js
index 45ab533..31a988d 100644
--- a/modules/bootstrap.js
+++ b/modules/bootstrap.js
@@ -1,6 +1,137 @@
-(function(exports) {
+(function(exports, importNativeModule) {
     "use strict";
 
-    // Do early initialization here.
+    const Importer = importNativeModule('_importer');
+    const Gio = Importer.importGIModule('Gio', '2.0');
 
-})(window);
+    let _exports = {};
+
+    function loadNativeModule(moduleID) {
+        _exports[moduleID] = importNativeModule(moduleID);
+    }
+
+    function runOverridesForGIModule(module, moduleID) {
+        let overridesModuleName = ('overrides/' + moduleID);
+        loadJSModule(overridesModuleName);
+        let overridesModule = _exports[overridesModuleName];
+        if (!overridesModule)
+            return;
+
+        let initFunc = overridesModule._init;
+        if (!initFunc)
+            return;
+
+        initFunc.call(module);
+    }
+
+    function importGIModuleWithOverrides(moduleID, moduleVersion) {
+        let exportedID = 'gi/' + moduleID;
+        if (_exports[exportedID])
+            return _exports[exportedID];
+
+        let module = Importer.importGIModule(moduleID, moduleVersion);
+        _exports[exportedID] = module;
+        _exports[exportedID + '/' + moduleVersion] = module;
+        runOverridesForGIModule(module, moduleID);
+        return module;
+    }
+
+    function loadGIModule(moduleID) {
+        if (!moduleID.startsWith('gi/'))
+            return;
+
+        let giModuleID = moduleID.slice(3);
+
+        let moduleVersion;
+        if (giModuleID.indexOf('/') >= 0)
+            [giModuleID, moduleVersion] = moduleVersion.split('/', 2);
+        else
+            moduleVersion = null;
+
+        importGIModuleWithOverrides(giModuleID, moduleVersion);
+    }
+
+    function createModuleScope(id, uri) {
+        let module = {};
+
+        Object.defineProperty(module, "id", { value: id,
+                                              configurable: false,
+                                              writable: false });
+        Object.defineProperty(module, "uri", { value: uri,
+                                               configurable: false,
+                                               writable: false });
+
+        let scope = {};
+        scope.module = module;
+
+        // XXX -- for compatibility with the old module system, we don't
+        // give modules their own private namespace, but simply export
+        // the module scope directly.
+        //
+        // This should eventually go away, when we fully adopt CommonJS.
+        scope.exports = scope;
+
+        return scope;
+    }
+
+    function loadJSModule(moduleID) {
+        function getModuleContents(modulePath) {
+            let file = Gio.File.new_for_commandline_arg(modulePath);
+
+            let success, script;
+            try {
+                [success, script] = file.load_contents(null);
+            } catch(e) {
+                return null;
+            }
+
+            return script;
+        }
+
+        function evalModule(modulePath, script) {
+            let scope = createModuleScope(moduleID, modulePath);
+            _exports[moduleID] = scope;
+
+            let evalSuccess = false;
+            try {
+                // Don't catch errors for the eval, as those should propagate
+                // back up to the user...
+                Importer.evalWithScope(scope, script, modulePath);
+                evalSuccess = true;
+            } finally {
+                if (!evalSuccess)
+                    delete _exports[moduleID];
+            }
+        }
+
+        for (let path of require.paths) {
+            let modulePath = path + '/' + moduleID + '.js';
+            let script = getModuleContents(modulePath);
+            if (!script)
+                continue;
+
+            evalModule(modulePath, script);
+        }
+    }
+
+    let require = exports.require = function require(moduleID) {
+        if (_exports[moduleID])
+            return _exports[moduleID];
+
+        const FINDERS = [
+            loadNativeModule,
+            loadGIModule,
+            loadJSModule,
+        ];
+
+        for (let finder of FINDERS) {
+            finder(moduleID);
+            if (_exports[moduleID])
+                return _exports[moduleID];
+        }
+
+        throw new Error("Could not load module '" + moduleID + "'");
+    }
+    require.paths = Importer.getBuiltinSearchPath();
+
+})(window, importNativeModule);
diff --git a/modules/cairo.js b/modules/cairo.js
index 7555c3c..8de7ab9 100644
--- a/modules/cairo.js
+++ b/modules/cairo.js
@@ -18,7 +18,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 
-const Lang = imports.lang;
+const Lang = require('lang');
 
 const Antialias = {
     DEFAULT: 0,
@@ -143,5 +143,4 @@ const SurfaceType = {
 };
 
 // Merge stuff defined in native code
-Lang.copyProperties(imports.cairoNative, this);
-
+Lang.copyProperties(require('cairoNative'), this);
diff --git a/modules/format.js b/modules/format.js
index bf3d0a7..d480c83 100644
--- a/modules/format.js
+++ b/modules/format.js
@@ -1,6 +1,6 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 
-const GjsPrivate = imports.gi.GjsPrivate;
+const GjsPrivate = require('gi/GjsPrivate');
 
 function vprintf(str, args) {
     let i = 0;
diff --git a/modules/gettext.js b/modules/gettext.js
index 60991e1..b2af482 100644
--- a/modules/gettext.js
+++ b/modules/gettext.js
@@ -24,7 +24,7 @@
  *
  * Usage:
  *
- * const Gettext = imports.gettext;
+ * const Gettext = require('gettext');
  *
  * Gettext.textdomain("myapp");
  * Gettext.bindtextdomain("myapp", "/usr/share/locale");
@@ -32,8 +32,8 @@
  * let translated = Gettext.gettext("Hello world!");
  */
 
-const GLib = imports.gi.GLib;
-const GjsPrivate = imports.gi.GjsPrivate;
+const GLib = require('gi/GLib');
+const GjsPrivate = require('gi/GjsPrivate');
 
 function textdomain(domain) {
     return GjsPrivate.textdomain(domain);
diff --git a/modules/importer.cpp b/modules/importer.cpp
new file mode 100644
index 0000000..10b3ed8
--- /dev/null
+++ b/modules/importer.cpp
@@ -0,0 +1,153 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright 2013 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <config.h>
+
+#include "importer.h"
+#include <gjs/gjs-module.h>
+#include <gjs/byteArray.h>
+#include "gi/ns.h"
+
+static JSBool
+import_gi_module(JSContext *context,
+                 unsigned   argc,
+                 jsval     *vp)
+{
+    JSBool ret = JS_FALSE;
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    jsval retval = JSVAL_VOID;
+    char *module_name = NULL;
+    char *module_version = NULL;
+    JSObject *module_obj;
+
+    if (!gjs_parse_call_args(context, "importGIModule", "s?s", args,
+                             "moduleName", &module_name,
+                             "moduleVersion", &module_version))
+        goto out;
+
+    if (!gjs_import_gi_module(context, module_name, module_version, &module_obj))
+        goto out;
+
+    ret = JS_TRUE;
+    args.rval().setObject(*module_obj);
+
+ out:
+    g_free(module_name);
+    g_free(module_version);
+    return ret;
+}
+
+static JSBool
+eval_with_scope(JSContext *context,
+                unsigned   argc,
+                jsval     *vp)
+{
+    JSBool ret = JS_FALSE;
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    JSObject *scope;
+    JSObject *script_obj;
+    guint8 *script;
+    gsize script_len;
+    char *filename = NULL;
+    jsval retval;
+
+    if (!gjs_parse_call_args(context, "evalWithScope", "oos", args,
+                             "scope", &scope,
+                             "script", &script_obj,
+                             "filename", &filename))
+        goto out;
+
+    gjs_byte_array_peek_data (context, script_obj, &script, &script_len);
+
+    if (!gjs_eval_with_scope(context, scope, (const char *) script, script_len, filename, &retval))
+        goto out;
+
+    ret = JS_TRUE;
+    args.rval().set(retval);
+
+ out:
+    g_free(filename);
+    return ret;
+}
+
+static JSBool
+get_builtin_search_path(JSContext *context,
+                        unsigned   argc,
+                        jsval     *vp)
+{
+    GjsContext *gjs_context = GJS_CONTEXT(JS_GetContextPrivate(context));
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    const char **context_search_path;
+    int context_search_path_length;
+    const char **global_search_path;
+    int global_search_path_length;
+    GArray *elems;
+    JSObject *search_path_obj;
+    int i;
+
+    context_search_path = gjs_context_get_search_path(gjs_context);
+    context_search_path_length = context_search_path ? g_strv_length((char **) context_search_path) : 0;
+    global_search_path = (const char **) gjs_get_search_path();
+    global_search_path_length = global_search_path ? g_strv_length((char **) global_search_path) : 0;
+
+    elems = g_array_sized_new(FALSE, FALSE, sizeof(jsval),
+                              context_search_path_length + global_search_path_length);
+
+    for (i = 0; i < context_search_path_length; i++) {
+        jsval element = STRING_TO_JSVAL(JS_NewStringCopyZ(context, context_search_path[i]));
+        g_array_append_val(elems, element);
+    }
+
+    for (i = 0; i < global_search_path_length; i++) {
+        jsval element = STRING_TO_JSVAL(JS_NewStringCopyZ(context, global_search_path[i]));
+        g_array_append_val(elems, element);
+    }
+
+    search_path_obj = JS_NewArrayObject(context, elems->len, (jsval *)elems->data);
+    g_array_free(elems, TRUE);
+
+    args.rval().setObject(*search_path_obj);
+    return JS_TRUE;
+}
+
+static JSFunctionSpec module_funcs[] = {
+    { "importGIModule", JSOP_WRAPPER (import_gi_module), 2, GJS_MODULE_PROP_FLAGS },
+    { "evalWithScope", JSOP_WRAPPER (eval_with_scope), 3, GJS_MODULE_PROP_FLAGS },
+    { "getBuiltinSearchPath", JSOP_WRAPPER (get_builtin_search_path), 0, GJS_MODULE_PROP_FLAGS },
+    { NULL },
+};
+
+JSBool
+gjs_js_define_importer_stuff(JSContext  *context,
+                             JSObject  **module_out)
+{
+    JSObject *module;
+
+    module = JS_NewObject(context, NULL, NULL, NULL);
+
+    if (!JS_DefineFunctions(context, module, &module_funcs[0]))
+        return JS_FALSE;
+
+    *module_out = module;
+    return JS_TRUE;
+}
diff --git a/modules/importer.h b/modules/importer.h
new file mode 100644
index 0000000..5fa25b0
--- /dev/null
+++ b/modules/importer.h
@@ -0,0 +1,38 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright 2013 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __GJS_MODULE_IMPORTER_H__
+#define __GJS_MODULE_IMPORTER_H__
+
+#include <config.h>
+#include <glib.h>
+#include "gjs/jsapi-util.h"
+
+G_BEGIN_DECLS
+
+JSBool        gjs_js_define_importer_stuff   (JSContext      *context,
+                                              JSObject      **module_out);
+
+G_END_DECLS
+
+#endif  /* __GJS_MODULE_IMPORTER_H__ */
diff --git a/modules/lang.js b/modules/lang.js
index 73de257..b6cc1c8 100644
--- a/modules/lang.js
+++ b/modules/lang.js
@@ -21,7 +21,7 @@
 
 // Utilities that are "meta-language" things like manipulating object props
 
-const Gi = imports._gi;
+const Gi = require('_gi');
 
 function countProperties(obj) {
     let count = 0;
diff --git a/modules/mainloop.js b/modules/mainloop.js
index 06458a3..3c7136b 100644
--- a/modules/mainloop.js
+++ b/modules/mainloop.js
@@ -21,8 +21,8 @@
 
 // A layer of convenience and backwards-compatibility over GLib MainLoop facilities
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
+const GLib = require('gi/GLib');
+const GObject = require('gi/GObject');
 
 var _mainLoops = {};
 
diff --git a/modules/modules.cpp b/modules/modules.cpp
index aae3569..0ccc432 100644
--- a/modules/modules.cpp
+++ b/modules/modules.cpp
@@ -32,6 +32,7 @@
 
 #include "system.h"
 #include "console.h"
+#include "importer.h"
 
 void
 gjs_register_static_modules (void)
@@ -40,5 +41,6 @@ gjs_register_static_modules (void)
     gjs_register_native_module("cairoNative", gjs_js_define_cairo_stuff);
 #endif
     gjs_register_native_module("system", gjs_js_define_system_stuff);
+    gjs_register_native_module("_importer", gjs_js_define_importer_stuff);
     gjs_register_native_module("console", gjs_define_console_stuff);
 }
diff --git a/modules/overrides/GLib.js b/modules/overrides/GLib.js
index 7ecbdcf..b91c593 100644
--- a/modules/overrides/GLib.js
+++ b/modules/overrides/GLib.js
@@ -18,7 +18,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 
-const ByteArray = imports.byteArray;
+const ByteArray = require('byteArray');
 
 let GLib;
 let originalVariantClass;
@@ -246,7 +246,7 @@ function _unpack_variant(variant, deep) {
 }
 
 function _init() {
-    // this is imports.gi.GLib
+    // this is require('gi/GLib');
 
     GLib = this;
 
@@ -280,6 +280,6 @@ function _init() {
     }
 
     this.Bytes.prototype.toArray = function() {
-       return imports.byteArray.fromGBytes(this);
+       return require('byteArray').fromGBytes(this);
     }
 }
diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js
index 7f783ae..027f390 100644
--- a/modules/overrides/GObject.js
+++ b/modules/overrides/GObject.js
@@ -18,8 +18,8 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 
-const Lang = imports.lang;
-const Gi = imports._gi;
+const Lang = require('lang');
+const Gi = require('_gi');
 
 let GObject;
 
diff --git a/modules/overrides/Gio.js b/modules/overrides/Gio.js
index eac26c4..533e275 100644
--- a/modules/overrides/Gio.js
+++ b/modules/overrides/Gio.js
@@ -18,11 +18,11 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 
-var GLib = imports.gi.GLib;
-var GObject = imports.gi.GObject;
-var GjsPrivate = imports.gi.GjsPrivate;
-var Lang = imports.lang;
-var Signals = imports.signals;
+const GLib = require('gi/GLib');
+const GObject = require('gi/GObject');
+const GjsPrivate = require('gi/GjsPrivate');
+const Lang = require('lang');
+const Signals = require('signals');
 var Gio;
 
 function _signatureLength(sig) {
diff --git a/modules/tweener/tweener.js b/modules/tweener/tweener.js
index 503dbf4..cb0b2c1 100644
--- a/modules/tweener/tweener.js
+++ b/modules/tweener/tweener.js
@@ -34,10 +34,11 @@
  http://code.google.com/p/tweener/wiki/License
  */
 
-const GLib = imports.gi.GLib;
+const GLib = require('gi/GLib');
 
-const TweenList = imports.tweener.tweenList;
-const Signals = imports.signals;
+const Equations = require('tweener/equations');
+const TweenList = require('tweener/tweenList');
+const Signals = require('signals');
 
 var _inited = false;
 var _engineExists = false;
@@ -517,13 +518,13 @@ function _addTweenOrCaller(target, tweeningParameters, isCaller) {
 
     // FIXME: Tweener allows you to use functions with an all lower-case name
     if (typeof obj.transition == "string") {
-        transition = imports.tweener.equations[obj.transition];
+        transition = Equations[obj.transition];
     } else {
         transition = obj.transition;
     }
 
     if (!transition)
-        transition = imports.tweener.equations["easeOutExpo"];
+        transition = Equations.easeOutExpo;
 
     var tween;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]