[gnome-maps/wip/mlundblad/es6-modules: 1/22] Migrate to ES6 modules




commit 59b12090cb938a7d25cab8c36a87d9456bc232c2
Author: Marcus Lundblad <ml dfupdate se>
Date:   Mon May 30 22:47:07 2022 +0200

    Migrate to ES6 modules
    
    Switch to using ES6 modules for internal
    modules and GI modules instead of using
    the legacy imports object.
    The unit tests are still using imports.jsunit
    as this is not available as an ES6 module
    (the preferred solution now is to use
    jasmine-gjs). imports.bytearray,
    imports.format, and imports.mainloop are
    covered in follow-up commits.

 src/address.js                          |   2 +-
 src/application.js                      | 165 +++++++--------
 src/boundingBox.js                      |   4 +-
 src/color.js                            |   8 +-
 src/constants.js                        |   8 +-
 src/contactPlace.js                     |  18 +-
 src/contextMenu.js                      | 106 +++++-----
 src/epaf.js                             |   4 +-
 src/exportViewDialog.js                 |  74 ++++---
 src/favoritesPopover.js                 |  60 +++---
 src/geoJSONShapeLayer.js                |  42 ++--
 src/geoJSONSource.js                    |  55 +++--
 src/geoJSONStyle.js                     |  19 +-
 src/geoclue.js                          |  59 +++---
 src/geocode.js                          |  12 +-
 src/geojson-vt/clip.js                  |   2 +-
 src/geojson-vt/convert.js               |   4 +-
 src/geojson-vt/index.js                 |  19 +-
 src/geojson-vt/simplify.js              |   2 +-
 src/geojson-vt/tile.js                  |   2 +-
 src/geojson-vt/transform.js             |   4 +-
 src/geojson-vt/wrap.js                  |   4 +-
 src/gfx.js                              |   4 +-
 src/gpxShapeLayer.js                    |  40 ++--
 src/graphHopper.js                      |  79 ++++---
 src/graphHopperGeocode.js               |  16 +-
 src/graphHopperTransit.js               |  48 ++---
 src/headerBar.js                        |  66 +++---
 src/http.js                             |   6 +-
 src/hvt.js                              | 280 ++++++++++++-------------
 src/instructionRow.js                   |  34 +--
 src/kmlShapeLayer.js                    |  47 ++---
 src/layersPopover.js                    |  88 ++++----
 src/location.js                         |  18 +-
 src/locationServiceDialog.js            |  28 +--
 src/longPrintLayout.js                  |  23 ++-
 src/main.js                             |  44 ++--
 src/mainWindow.js                       | 138 ++++++-------
 src/mapBubble.js                        |  46 +++--
 src/mapMarker.js                        |  91 ++++----
 src/mapSource.js                        |  16 +-
 src/mapView.js                          | 283 ++++++++++++-------------
 src/mapWalker.js                        |  50 ++---
 src/meson.build                         |   3 +
 src/org.gnome.Maps.in                   |  14 +-
 src/org.gnome.Maps.src.gresource.xml.in |  16 ++
 src/osmAccountDialog.js                 |  45 ++--
 src/osmConnection.js                    |  86 ++++----
 src/osmEdit.js                          |  42 ++--
 src/osmEditDialog.js                    | 149 +++++++-------
 src/osmNames.js                         |   6 +-
 src/osmTypeListRow.js                   |  20 +-
 src/osmTypePopover.js                   |  42 ++--
 src/osmTypeSearchEntry.js               |  27 +--
 src/osmTypes.js                         |  16 +-
 src/osmUtils.js                         |   8 +-
 src/overpass.js                         |  44 ++--
 src/photonGeocode.js                    |  16 +-
 src/photonParser.js                     |  90 ++++----
 src/place.js                            | 256 ++++++++++++-----------
 src/placeBar.js                         |  95 ++++-----
 src/placeButtons.js                     |  72 ++++---
 src/placeDialog.js                      |  34 +--
 src/placeEntry.js                       |  84 ++++----
 src/placeFormatter.js                   |  16 +-
 src/placeIcons.js                       |   2 +-
 src/placeListRow.js                     |  44 ++--
 src/placeMarker.js                      |  15 +-
 src/placePopover.js                     |  55 ++---
 src/placeStore.js                       | 161 ++++++++-------
 src/placeView.js                        |  79 +++----
 src/placeViewImage.js                   |  19 +-
 src/placeZoom.js                        |   2 +-
 src/printLayout.js                      |  87 +++-----
 src/printOperation.js                   |  34 ++-
 src/route.js                            | 114 +++++-----
 src/routeEntry.js                       |  77 +++----
 src/routeQuery.js                       | 136 ++++++------
 src/routingDelegator.js                 |  14 +-
 src/searchPopover.js                    |  20 +-
 src/sendToDialog.js                     | 121 ++++++-----
 src/service.js                          |  10 +-
 src/settings.js                         |  69 ++++---
 src/shapeLayer.js                       |  47 +++--
 src/shortPrintLayout.js                 |  19 +-
 src/sidebar.js                          | 131 ++++++------
 src/storedRoute.js                      | 133 ++++++------
 src/time.js                             |  15 +-
 src/togeojson/togeojson.js              |   4 +-
 src/transit.js                          |  12 +-
 src/transitArrivalMarker.js             |  35 ++--
 src/transitArrivalRow.js                |  38 ++--
 src/transitBoardMarker.js               |  44 ++--
 src/transitItineraryRow.js              |  35 ++--
 src/transitLegRow.js                    |  85 ++++----
 src/transitMoreRow.js                   |  28 +--
 src/transitOptions.js                   |  34 +--
 src/transitOptionsPanel.js              |  58 +++---
 src/transitPlan.js                      | 141 ++++---------
 src/transitPrintLayout.js               |  50 ++---
 src/transitRouteLabel.js                |  28 +--
 src/transitRouter.js                    |  79 +++----
 src/transitStopRow.js                   |  33 +--
 src/transitWalkMarker.js                |  30 +--
 src/transitplugins/goMetro.js           |  33 +--
 src/transitplugins/openTripPlanner.js   | 172 ++++++++--------
 src/transitplugins/opendataCH.js        |  88 ++++----
 src/transitplugins/resrobot.js          |  86 ++++----
 src/translations.js                     |  22 +-
 src/turnPointMarker.js                  |  70 ++++---
 src/uris.js                             |  16 +-
 src/userLocationMarker.js               |  44 ++--
 src/utils.js                            | 108 +++++-----
 src/wikipedia.js                        |  20 +-
 src/xmldom/dom.js                       |   4 +-
 src/xmldom/domparser.js                 |   8 +-
 src/xmldom/sax.js                       |   4 +-
 src/zoomInDialog.js                     |  33 +--
 tests/addressTest.js                    |   8 +-
 tests/boundingBoxTest.js                |  52 ++---
 tests/colorTest.js                      |  14 +-
 tests/meson.build                       |  34 ++-
 tests/osmNamesTest.js                   |  34 +--
 tests/placeIconsTest.js                 |  10 +-
 tests/placeZoomTest.js                  |  35 ++--
 tests/test.in                           |  16 +-
 tests/timeTest.js                       |  18 +-
 tests/translationsTest.js               | 355 ++++++++++++++++----------------
 tests/urisTest.js                       |  18 +-
 tests/utilsTest.js                      |  56 ++---
 tests/wikipediaTest.js                  |  34 ++-
 131 files changed, 3485 insertions(+), 3344 deletions(-)
---
diff --git a/src/address.js b/src/address.js
index 8401e829..47ee8696 100644
--- a/src/address.js
+++ b/src/address.js
@@ -121,7 +121,7 @@ const FORMAT_MAP = {
     'VN': 'số %2$s %1$s'
 }
 
-function streetAddressForCountryCode(streetName, housenumber, countryCode) {
+export function streetAddressForCountryCode(streetName, housenumber, countryCode) {
     let format = FORMAT_MAP[countryCode];
 
     if (format)
diff --git a/src/application.js b/src/application.js
index 385061d5..fc5020a3 100644
--- a/src/application.js
+++ b/src/application.js
@@ -20,68 +20,54 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const Gtk = imports.gi.Gtk;
-const GtkClutter = imports.gi.GtkClutter;
-const Hdy = imports.gi.Handy;
-
-const ContactPlace = imports.contactPlace;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Geocode from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import Gtk from 'gi://Gtk';
+import GtkClutter from 'gi://GtkClutter';
+import Hdy from 'gi://Handy';
+
+import {ContactPlace} from './contactPlace.js';
 const Format = imports.format;
-const Geoclue = imports.geoclue;
-const GeocodeFactory = imports.geocode;
-const MainWindow = imports.mainWindow;
-const Maps = imports.gi.GnomeMaps;
-const OSMEdit = imports.osmEdit;
-const OSMTypeSearchEntry = imports.osmTypeSearchEntry;
-const PlaceStore = imports.placeStore;
-const RoutingDelegator = imports.routingDelegator;
-const RouteQuery = imports.routeQuery;
-const Settings = imports.settings;
-const Utils = imports.utils;
-const URIS = imports.uris;
-
-// used globally
-var application = null;
-var settings = null;
-var placeStore = null;
-var routingDelegator = null;
-var geoclue = null;
-var contactStore = null;
-var osmEdit = null;
-var normalStartup = true;
-var routeQuery = null;
-
-const _ensuredTypes = [OSMTypeSearchEntry.OSMTypeSearchEntry];
-
-var Application = GObject.registerClass({
-    Properties: {
-        'selected-place': GObject.ParamSpec.object('selected-place',
-                                                   'Selected Place',
-                                                   'The selected place',
-                                                   GObject.ParamFlags.READABLE |
-                                                   GObject.ParamFlags.WRITABLE,
-                                                   Geocode.Place),
-        'adaptive-mode': GObject.ParamSpec.boolean('adaptive-mode',
-                                                   'Adaptive Move',
-                                                   'Whether the main window is in adaptive (narrow) mode',
-                                                   GObject.ParamFlags.READABLE |
-                                                   GObject.ParamFlags.WRITABLE),
-    },
-}, class Application extends Gtk.Application {
-
-    _init() {
+import {Geoclue} from './geoclue.js';
+import * as GeocodeFactory from './geocode.js';
+import {MainWindow} from './mainWindow.js';
+import GnomeMaps from 'gi://GnomeMaps';
+import {OSMEdit} from './osmEdit.js';
+import {OSMTypeSearchEntry} from './osmTypeSearchEntry.js';
+import {PlaceStore} from './placeStore.js';
+import {RoutingDelegator} from './routingDelegator.js';
+import {RouteQuery} from './routeQuery.js';
+import {Settings} from './settings.js';
+import * as Utils from './utils.js';
+import * as URIS from './uris.js';
+
+const _ensuredTypes = [OSMTypeSearchEntry];
+
+export class Application extends Gtk.Application {
+
+    // used globally
+    static application = null;
+    static settings = null;
+    static placeStore = null;
+    static routingDelegator = null;
+    static geoclue = null;
+    static contactStore = null;
+    static osmEdit = null;
+    static normalStartup = true;
+    static routeQuery = null;
+
+    constructor() {
         /* Translators: This is the program name. */
         GLib.set_application_name(_("Maps"));
 
         /* Needed to be able to use in UI files */
         _ensuredTypes.forEach((type) => GObject.type_ensure(type));
 
-        super._init({ application_id: pkg.name,
-                      flags: Gio.ApplicationFlags.HANDLES_OPEN |
-                             Gio.ApplicationFlags.HANDLES_COMMAND_LINE });
+        super({ application_id: pkg.name,
+                flags: Gio.ApplicationFlags.HANDLES_OPEN |
+                       Gio.ApplicationFlags.HANDLES_COMMAND_LINE });
 
         this.add_main_option('local',
                              0,
@@ -149,7 +135,8 @@ var Application = GObject.registerClass({
     }
 
     _onOsmAccountSetupActivate() {
-        let dialog = osmEdit.createAccountDialog(this._mainWindow, false);
+        let dialog =
+            Application.osmEdit.createAccountDialog(this._mainWindow, false);
 
         dialog.show();
         dialog.connect('response', () => dialog.destroy());
@@ -170,7 +157,7 @@ var Application = GObject.registerClass({
     }
 
     _addContacts() {
-        let contacts = contactStore.get_contacts();
+        let contacts = Application.contactStore.get_contacts();
 
         this._addContactsRecursive(contacts, 0);
     }
@@ -185,9 +172,9 @@ var Application = GObject.registerClass({
                         return
 
                     Utils.debug('Adding contact address: ' + p.name);
-                    let place = new ContactPlace.ContactPlace({ place: p,
-                                                                contact: contact });
-                    placeStore.addPlace(place, PlaceStore.PlaceType.CONTACT);
+                    let place = new ContactPlace({ place: p, contact: contact });
+
+                    Application.placeStore.addPlace(place, PlaceStore.PlaceType.CONTACT);
                 });
 
                 this._addContactsRecursive(contacts, index + 1);
@@ -196,22 +183,22 @@ var Application = GObject.registerClass({
     }
 
     _initPlaceStore() {
-        placeStore = new PlaceStore.PlaceStore({
-            recentPlacesLimit: settings.get('recent-places-limit'),
-            recentRoutesLimit: settings.get('recent-routes-limit')
+        Application.placeStore = new PlaceStore({
+            recentPlacesLimit: Application.settings.get('recent-places-limit'),
+            recentRoutesLimit: Application.settings.get('recent-routes-limit')
         });
         try {
-            placeStore.load();
+            Application.placeStore.load();
         } catch (e) {
             log('Failed to parse Maps places file, ' +
                 'subsequent writes will overwrite the file!');
         }
 
-        if (contactStore.state === Maps.ContactStoreState.LOADED) {
+        if (Application.contactStore.state === GnomeMaps.ContactStoreState.LOADED) {
             this._addContacts();
         } else {
-            Utils.once(contactStore, 'notify::state', () => {
-                if (contactStore.state === Maps.ContactStoreState.LOADED)
+            Utils.once(Application.contactStore, 'notify::state', () => {
+                if (Application.contactStore.state === GnomeMaps.ContactStoreState.LOADED)
                     this._addContacts();
             });
         }
@@ -225,7 +212,7 @@ var Application = GObject.registerClass({
 
         Utils.loadStyleSheet(Gio.file_new_for_uri('resource:///org/gnome/Maps/application.css'));
 
-        application = this;
+        Application.application = this;
         this._initServices();
 
         Utils.addActions(this, {
@@ -244,7 +231,7 @@ var Application = GObject.registerClass({
                 onActivate: () => this.quit(),
                 accels: ['<Primary>Q']
             }
-        }, settings);
+        }, Application.settings);
 
 
         this._styleManager = Hdy.StyleManager.get_default();
@@ -256,20 +243,20 @@ var Application = GObject.registerClass({
     }
 
     _initServices() {
-        settings         = Settings.getSettings('org.gnome.Maps');
-        routeQuery       = new RouteQuery.RouteQuery();
-        routingDelegator = new RoutingDelegator.RoutingDelegator({ query: routeQuery });
-        geoclue          = new Geoclue.Geoclue();
-        contactStore = new Maps.ContactStore();
-        contactStore.load();
-        osmEdit = new OSMEdit.OSMEdit();
+        Application.settings = Settings.getSettings('org.gnome.Maps');
+        Application.routeQuery = new RouteQuery();
+        Application.routingDelegator = new RoutingDelegator({ query: Application.routeQuery });
+        Application.geoclue = new Geoclue();
+        Application.contactStore = new GnomeMaps.ContactStore();
+        Application.contactStore.load();
+        Application.osmEdit = new OSMEdit();
     }
 
     _createWindow() {
         if (this._mainWindow)
             return;
 
-        this._mainWindow = new MainWindow.MainWindow({ application: this });
+        this._mainWindow = new MainWindow({ application: this });
         this._mainWindow.connect('destroy', () => this._onWindowDestroy());
         if (GLib.getenv('MAPS_DEBUG') === 'focus') {
             this._mainWindow.connect('set-focus', (window, widget) => {
@@ -329,7 +316,7 @@ var Application = GObject.registerClass({
         /* unless there's exactly one place (which should be focused) in
          * the results, let the stored location be used on startup
          */
-        normalStartup = true;
+        Application.normalStartup = true;
         this.connect('shutdown', () => cancellable.cancel());
         GeocodeFactory.getGeocoder().search(query, null, null, cancellable,
                                             (places, error) => {
@@ -349,7 +336,7 @@ var Application = GObject.registerClass({
                         /* don't use the stored location on startup, as we're
                          * zooming in directly on the place
                          */
-                        normalStartup = false;
+                        Application.normalStartup = false;
                         this._mainWindow.mapView.showPlace(places[0], true);
                     } else {
                         this._mainWindow.placeEntry.grab_focus();
@@ -378,7 +365,7 @@ var Application = GObject.registerClass({
         let uri = files[0].get_uri();
 
         if (GLib.uri_parse_scheme(uri) !== 'maps')
-            normalStartup = false;
+            Application.normalStartup = false;
 
         this.activate();
 
@@ -443,4 +430,20 @@ var Application = GObject.registerClass({
     _onWindowDestroy(window) {
         this._mainWindow = null;
     }
-});
+}
+
+GObject.registerClass({
+    Properties: {
+        'selected-place': GObject.ParamSpec.object('selected-place',
+                                                   'Selected Place',
+                                                   'The selected place',
+                                                   GObject.ParamFlags.READABLE |
+                                                   GObject.ParamFlags.WRITABLE,
+                                                   Geocode.Place),
+        'adaptive-mode': GObject.ParamSpec.boolean('adaptive-mode',
+                                                   'Adaptive Move',
+                                                   'Whether the main window is in adaptive (narrow) mode',
+                                                   GObject.ParamFlags.READABLE |
+                                                   GObject.ParamFlags.WRITABLE),
+    }
+}, Application);
diff --git a/src/boundingBox.js b/src/boundingBox.js
index 0c06875e..396db2ca 100644
--- a/src/boundingBox.js
+++ b/src/boundingBox.js
@@ -19,9 +19,9 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Constants = imports.constants;
+import * as Constants from './constants.js';
 
-var BoundingBox = class {
+export class BoundingBox {
     constructor(params) {
         /* default to a bounding box the "opposite" of covering the whole
          * visible world, this way extending with a coordinate will ensure
diff --git a/src/color.js b/src/color.js
index 36f21f24..a51dd1c9 100644
--- a/src/color.js
+++ b/src/color.js
@@ -27,7 +27,7 @@ const MIN_CONTRAST_RATIO = 2.0;
  * from a hex-encoded color string. Optionally, if defaultValue is supplied,
  * fallback to that if color is undefined.
  */
-function parseColor(color, component, defaultValue) {
+export function parseColor(color, component, defaultValue) {
     if (color) {
         let index = component * 2;
         return parseInt(color.substring(index, index + 2), 16) / 255;
@@ -41,7 +41,7 @@ function parseColor(color, component, defaultValue) {
  * notation (i.e. ffffff for white) according to the W3C WCAG definition:
  * https://www.w3.org/WAI/GL/wiki/Relative_luminance
  */
-function relativeLuminance(color) {
+export function relativeLuminance(color) {
     let rsRGB = parseColor(color, 0);
     let gsRGB = parseColor(color, 1);
     let bsRGB = parseColor(color, 2);
@@ -60,7 +60,7 @@ function relativeLuminance(color) {
  * (i.e. ffffff for white) according to the W3C WCAG definition:
  * https://www.w3.org/WAI/GL/wiki/Contrast_ratio
  */
-function contrastRatio(color1, color2) {
+export function contrastRatio(color1, color2) {
     let lc1 = relativeLuminance(color1);
     let lc2 = relativeLuminance(color2);
     /* order by luminance, lighter before darker */
@@ -76,7 +76,7 @@ function contrastRatio(color1, color2) {
  * has enough contrast against the background, otherwise (or if that argument
  * is undefined), return the one of black or white giving the highest contrast
  */
-function getContrastingForegroundColor(backgroundColor,
+export function getContrastingForegroundColor(backgroundColor,
                                        desiredForegroundColor) {
     if (!desiredForegroundColor ||
         (contrastRatio(backgroundColor, desiredForegroundColor) <
diff --git a/src/constants.js b/src/constants.js
index a3419ec7..43a7635e 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -22,7 +22,7 @@
 /**
  * Constraints of visible location in the standard Mercaartor projection.
  */
-var MIN_LATITUDE = -85.0511287798;
-var MAX_LATITUDE = 85.0511287798;
-var MIN_LONGITUDE = -180;
-var MAX_LONGITUDE = 180;
+export var MIN_LATITUDE = -85.0511287798;
+export var MAX_LATITUDE = 85.0511287798;
+export var MIN_LONGITUDE = -180;
+export var MAX_LONGITUDE = 180;
diff --git a/src/contactPlace.js b/src/contactPlace.js
index 6c036c22..255d0e9f 100644
--- a/src/contactPlace.js
+++ b/src/contactPlace.js
@@ -19,18 +19,18 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GObject = imports.gi.GObject;
+import GObject from 'gi://GObject';
 
-const Place = imports.place;
+import {Place} from './place.js';
 
-var ContactPlace = GObject.registerClass(
-class ContactPlace extends Place.Place {
-    _init(params) {
-        this._contact = params.contact;
+export class ContactPlace extends Place {
+    constructor(params) {
+        let contact = params.contact;
         delete params.contact;
 
         params.store = false;
-        super._init(params);
+        super(params);
+        this._contact = contact;
     }
 
     get icon() {
@@ -42,4 +42,6 @@ class ContactPlace extends Place.Place {
                 this.osm_type,
                 this.osm_id].join('-');
     }
-});
+}
+
+GObject.registerClass(ContactPlace);
diff --git a/src/contextMenu.js b/src/contextMenu.js
index 6de6a8c8..88b93dbe 100644
--- a/src/contextMenu.js
+++ b/src/contextMenu.js
@@ -19,41 +19,35 @@
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const Gdk = imports.gi.Gdk;
-const Geocode = imports.gi.GeocodeGlib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gdk from 'gi://Gdk';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const GeocodeFactory = imports.geocode;
-const Location = imports.location;
-const OSMAccountDialog = imports.osmAccountDialog;
-const OSMEdit = imports.osmEdit;
-const OSMEditDialog = imports.osmEditDialog;
-const Place = imports.place;
-const RouteQuery = imports.routeQuery;
-const Utils = imports.utils;
-const ZoomInDialog = imports.zoomInDialog;
-
-var ContextMenu = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/context-menu.ui',
-    InternalChildren: [ 'whatsHereItem',
-                        'geoURIItem',
-                        'addOSMLocationItem',
-                        'routeFromHereItem',
-                        'addIntermediateDestinationItem',
-                        'routeToHereItem' ],
-}, class ContextMenu extends Gtk.Menu {
-    _init(params) {
-        this._mapView = params.mapView;
+import {Application} from './application.js';
+import * as GeocodeFactory from './geocode.js';
+import {Location} from './location.js';
+import {OSMAccountDialog} from './osmAccountDialog.js';
+import {OSMEdit} from './osmEdit.js';
+import {OSMEditDialog} from './osmEditDialog.js';
+import {Place} from './place.js';
+import {RouteQuery} from './routeQuery.js';
+import * as Utils from './utils.js';
+import {ZoomInDialog} from './zoomInDialog.js';
+
+export class ContextMenu extends Gtk.Menu {
+    constructor(params) {
+        let mapView = params.mapView;
         delete params.mapView;
 
-        this._mainWindow = params.mainWindow;
+        let mainWindow = params.mainWindow;
         delete params.mainWindow;
 
-        super._init(params);
+        super(params);
 
+        this._mapView = mapView;
+        this._mainWindow = mainWindow;
         this._buttonGesture =
             new Gtk.GestureSingle({ widget: this._mapView,
                                     button: Gdk.BUTTON_SECONDARY });
@@ -98,30 +92,30 @@ var ContextMenu = GObject.registerClass({
 
     _onRouteFromHereActivated() {
         let query = Application.routeQuery;
-        let location = new Location.Location({ latitude: this._latitude,
-                                               longitude: this._longitude,
-                                               accuracy: 0 });
-        let place = new Place.Place({ location: location, store: false });
+        let location = new Location({ latitude: this._latitude,
+                                      longitude: this._longitude,
+                                      accuracy: 0 });
+        let place = new Place({ location: location, store: false });
 
         query.points[0].place = place;
     }
 
     _onRouteToHereActivated() {
         let query = Application.routeQuery;
-        let location = new Location.Location({ latitude: this._latitude,
-                                               longitude: this._longitude,
-                                               accuracy: 0 });
-        let place = new Place.Place({ location: location, store: false });
+        let location = new Location({ latitude: this._latitude,
+                                      longitude: this._longitude,
+                                      accuracy: 0 });
+        let place = new Place({ location: location, store: false });
 
         query.points.last().place = place;
     }
 
     _onAddIntermediateDestinationActivated() {
         let query = Application.routeQuery;
-        let location = new Location.Location({ latitude: this._latitude,
-                                               longitude: this._longitude,
-                                               accuracy: 0 });
-        let place = new Place.Place({ location: location, store: false });
+        let location = new Location({ latitude: this._latitude,
+                                      longitude: this._longitude,
+                                      accuracy: 0 });
+        let place = new Place({ location: location, store: false });
 
         query.addPoint(-1).place = place;
     }
@@ -140,12 +134,12 @@ var ContextMenu = GObject.registerClass({
     }
 
     _onGeoURIActivated() {
-        let location = new Location.Location({ latitude: this._latitude,
-                                               longitude: this._longitude,
-                                               accuracy: 0 });
+        let location = new Location({ latitude: this._latitude,
+                                      longitude: this._longitude,
+                                      accuracy: 0 });
         let display = Gdk.Display.get_default();
         let clipboard = Gtk.Clipboard.get_default(display);
-        let uri = location.to_uri(Geocode.LocationURIScheme.GEO);
+        let uri = location.to_uri(GeocodeGlib.LocationURIScheme.GEO);
 
         clipboard.set_text(uri, uri.length);
     }
@@ -174,11 +168,11 @@ var ContextMenu = GObject.registerClass({
 
         if (this._mapView.view.get_zoom_level() < OSMEdit.MIN_ADD_LOCATION_ZOOM_LEVEL) {
             let zoomInDialog =
-                new ZoomInDialog.ZoomInDialog({ longitude: this._longitude,
-                                                latitude: this._latitude,
-                                                view: this._mapView.view,
-                                                transient_for: this._mainWindow,
-                                                modal: true });
+                new ZoomInDialog({ longitude: this._longitude,
+                                   latitude: this._latitude,
+                                   view: this._mapView.view,
+                                   transient_for: this._mainWindow,
+                                   modal: true });
 
             zoomInDialog.connect('response', () => zoomInDialog.destroy());
             zoomInDialog.show_all();
@@ -187,7 +181,7 @@ var ContextMenu = GObject.registerClass({
 
         let dialog =
             osmEdit.createEditNewDialog(this._mainWindow,
-                                      this._latitude, this._longitude);
+                                        this._latitude, this._longitude);
 
         dialog.show();
         dialog.connect('response', (dialog, response) => {
@@ -198,4 +192,14 @@ var ContextMenu = GObject.registerClass({
             }
         });
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/context-menu.ui',
+    InternalChildren: [ 'whatsHereItem',
+                        'geoURIItem',
+                        'addOSMLocationItem',
+                        'routeFromHereItem',
+                        'addIntermediateDestinationItem',
+                        'routeToHereItem' ],
+}, ContextMenu);
diff --git a/src/epaf.js b/src/epaf.js
index 4465a730..8235e8f5 100644
--- a/src/epaf.js
+++ b/src/epaf.js
@@ -23,7 +23,7 @@
 // Google encoded polyline decoder
 // https://developers.google.com/maps/documentation/utilities/polylinealgorithm
 
-const Champlain = imports.gi.Champlain;
+import Champlain from 'gi://Champlain';
 
 function _decodeValue(data, index) {
     let b;
@@ -45,7 +45,7 @@ function _decodeValue(data, index) {
     return [ret_val, index];
 }
 
-function decode(data) {
+export function decode(data) {
     let length = data.length;
     let polyline = [];
     let index = 0;
diff --git a/src/exportViewDialog.js b/src/exportViewDialog.js
index 42b7996d..baffe2e1 100644
--- a/src/exportViewDialog.js
+++ b/src/exportViewDialog.js
@@ -17,48 +17,43 @@
  * Author: Jonas Danielson <jonas threetimestwo org>
  */
 
-const Cairo = imports.cairo;
-const Gdk = imports.gi.Gdk;
-const GLib = imports.gi.GLib;
-const Gio = imports.gi.Gio;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Cairo from 'cairo';
+import Gdk from 'gi://Gdk';
+import GLib from 'gi://GLib';
+import Gio from 'gi://Gio';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Utils = imports.utils;
-
-var Response = {
-    SUCCESS: 0,
-    CANCEL: 1
-};
+import * as Utils from './utils.js';
 
 const _PREVIEW_WIDTH = 150;
 
-var ExportViewDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/export-view-dialog.ui',
-    InternalChildren: [ 'exportButton',
-                        'cancelButton',
-                        'filenameEntry',
-                        'fileChooserButton',
-                        'previewArea',
-                        'layersCheckButton' ],
-}, class ExportViewDialog extends Gtk.Dialog {
-    _init(params) {
-        this._surface = params.surface;
+export class ExportViewDialog extends Gtk.Dialog {
+
+    static Response = {
+        SUCCESS: 0,
+        CANCEL: 1
+    };
+
+    constructor(params) {
+        let surface = params.surface;
         delete params.surface;
 
-        this._latitude = params.latitude;
+        let latitude = params.latitude;
         delete params.latitude;
 
-        this._longitude = params.longitude;
+        let longitude = params.longitude;
         delete params.longitude;
 
-        this._mapView = params.mapView;
+        let mapView = params.mapView;
         delete params.mapView;
 
         params.use_header_bar = true;
-        super._init(params);
+        super(params);
 
-        this._cancelButton.connect('clicked', () => this.response(Response.CANCEL));
+        this._surface = surface;
+        this._mapView = mapView;
+        this._cancelButton.connect('clicked', () => this.response(ExportViewDialog.Response.CANCEL));
         this._exportButton.connect('clicked', () => this._exportView());
         this._filenameEntry.connect('changed', () => this._onFileNameChanged());
         this._fileChooserButton.connect('file-set', () => this._onFolderChanged());
@@ -69,18 +64,19 @@ var ExportViewDialog = GObject.registerClass({
         if (!this._folder)
             this._folder = GLib.get_user_data_dir();
 
-        this._filenameEntry.text = this._fileName = this._getName();
+        this._filenameEntry.text = this._fileName =
+            this._getName(latitude, longitude);
         this._fileChooserButton.set_current_folder(this._folder);
         this._setupPreviewArea();
     }
 
-    _getName() {
+    _getName(latitude, longitude) {
         /* Translators: This is a format string for a PNG filename for an
          * exported image with coordinates. The .png extension should be kept
          * intact in the translated string.
          */
-        return _("Maps at %f, %f.png").format(this._latitude.toFixed(2),
-                                              this._longitude.toFixed(2));
+        return _("Maps at %f, %f.png").format(latitude.toFixed(2),
+                                              longitude.toFixed(2));
     }
 
     _setupPreviewArea() {
@@ -145,7 +141,7 @@ var ExportViewDialog = GObject.registerClass({
 
         try {
             pixbuf.savev(path, "png", [], []);
-            this.response(Response.SUCCESS);
+            this.response(ExportViewDialog.Response.SUCCESS);
         } catch(e) {
             Utils.debug('failed to export view: ' + e.message);
             let details = null;
@@ -180,4 +176,14 @@ var ExportViewDialog = GObject.registerClass({
         this._surface = this._mapView.view.to_surface(includeLayers);
         this._previewArea.queue_draw();
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/export-view-dialog.ui',
+    InternalChildren: [ 'exportButton',
+                        'cancelButton',
+                        'filenameEntry',
+                        'fileChooserButton',
+                        'previewArea',
+                        'layersCheckButton' ],
+}, ExportViewDialog);
diff --git a/src/favoritesPopover.js b/src/favoritesPopover.js
index 097c1e58..45d8fe15 100644
--- a/src/favoritesPopover.js
+++ b/src/favoritesPopover.js
@@ -17,41 +17,26 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Application = imports.application;
-const PlaceListRow = imports.placeListRow;
-const PlaceStore = imports.placeStore;
+import {Application} from './application.js';
+import {PlaceListRow} from './placeListRow.js';
+import {PlaceStore} from './placeStore.js';
 
 const _N_VISIBLE = 6;
 
-var FavoritesPopover = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/favorites-popover.ui',
-    InternalChildren: [ 'mainGrid',
-                        'entry',
-                        'scrolledWindow',
-                        'list' ],
-    Properties: {
-        'rows': GObject.ParamSpec.int('rows',
-                                        '',
-                                        '',
-                                        GObject.ParamFlags.READABLE |
-                                        GObject.ParamFlags.WRITABLE,
-                                        0, GLib.MAXINT32, 0)
-    }
-}, class FavoritesPopover extends Gtk.Popover {
-
-    _init(params) {
-        params = params || { };
+export class FavoritesPopover extends Gtk.Popover {
 
-        this._mapView = params.mapView;
+    constructor(params) {
+        let mapView = params.mapView;
         delete params.mapView;
 
         params.transitions_enabled = false;
-        super._init(params);
+        super(params);
 
+        this._mapView = mapView;
         this._rows = 0;
 
         let placeType = PlaceStore.PlaceType.FAVORITE;
@@ -81,7 +66,7 @@ var FavoritesPopover = GObject.registerClass({
 
         this._list.connect('row-activated', (list, row) => {
             this.hide();
-            this._mapView.showPlace(row.place, true);
+            mapView.showPlace(row.place, true);
         });
 
         this._list.set_filter_func((row) => {
@@ -108,13 +93,28 @@ var FavoritesPopover = GObject.registerClass({
         let rows = 0;
         this._model.foreach((model, path, iter) => {
             let place = model.get_value(iter, PlaceStore.Columns.PLACE);
+            let row = new PlaceListRow({ place: place, can_focus: true });
 
-            let row = new PlaceListRow.PlaceListRow({ place: place,
-                                                      can_focus: true });
             this._list.insert(row, -1);
             rows++;
         });
 
         this.rows = rows;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/favorites-popover.ui',
+    InternalChildren: [ 'mainGrid',
+                        'entry',
+                        'scrolledWindow',
+                        'list' ],
+    Properties: {
+        'rows': GObject.ParamSpec.int('rows',
+                                        '',
+                                        '',
+                                        GObject.ParamFlags.READABLE |
+                                        GObject.ParamFlags.WRITABLE,
+                                        0, GLib.MAXINT32, 0)
+    }
+}, FavoritesPopover);
diff --git a/src/geoJSONShapeLayer.js b/src/geoJSONShapeLayer.js
index 5b9b1b1b..68ab7fbd 100644
--- a/src/geoJSONShapeLayer.js
+++ b/src/geoJSONShapeLayer.js
@@ -17,22 +17,28 @@
  * Author: Hashem Nasarat <hashem riseup net>
  */
 
-const GObject = imports.gi.GObject;
+import GObject from 'gi://GObject';
 
-const GeoJSONSource = imports.geoJSONSource;
-const ShapeLayer = imports.shapeLayer;
-const Utils = imports.utils;
+import {GeoJSONSource} from './geoJSONSource.js';
+import {ShapeLayer} from './shapeLayer.js';
+import * as Utils from './utils.js';
 
-var GeoJSONShapeLayer = GObject.registerClass(
-class GeoJSONShapeLayer extends ShapeLayer.ShapeLayer {
+export class GeoJSONShapeLayer extends ShapeLayer {
 
-    _init(params) {
-        super._init(params);
+    static mimeTypes = ['application/vnd.geo+json',
+                        'application/geo+json',
+                        'application/json'];
+    static displayName = 'GeoJSON';
 
-        this._mapSource = new GeoJSONSource.GeoJSONSource({
-            mapView: this._mapView,
-            markerLayer: this._markerLayer
-        });
+    static createInstance(params) {
+        return new GeoJSONShapeLayer(params);
+    };
+
+    constructor(params) {
+        super(params);
+
+        this._mapSource = new GeoJSONSource({ mapView: this._mapView,
+                                              markerLayer: this._markerLayer });
     }
 
     getName() {
@@ -47,12 +53,6 @@ class GeoJSONShapeLayer extends ShapeLayer.ShapeLayer {
     _parseContent() {
         this._mapSource.parse(JSON.parse(Utils.getBufferText(this._fileContents)));
     }
-});
-
-GeoJSONShapeLayer.mimeTypes = ['application/vnd.geo+json',
-                               'application/geo+json',
-                               'application/json'];
-GeoJSONShapeLayer.displayName = 'GeoJSON';
-GeoJSONShapeLayer.createInstance = function(params) {
-    return new GeoJSONShapeLayer(params);
-};
+}
+
+GObject.registerClass(GeoJSONShapeLayer);
diff --git a/src/geoJSONSource.js b/src/geoJSONSource.js
index 0027ded1..9be53e92 100644
--- a/src/geoJSONSource.js
+++ b/src/geoJSONSource.js
@@ -18,35 +18,34 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Cairo = imports.cairo;
-const Champlain = imports.gi.Champlain;
-const Clutter = imports.gi.Clutter;
-const GObject = imports.gi.GObject;
+import Cairo from 'cairo';
+import Champlain from 'gi://Champlain';
+import Clutter from 'gi://Clutter';
+import GObject from 'gi://GObject';
 const Mainloop = imports.mainloop;
 
-const BoundingBox = imports.boundingBox;
-const Geojsonvt = imports.geojsonvt.geojsonvt;
-const Location = imports.location;
-const Place = imports.place;
-const PlaceMarker = imports.placeMarker;
-const Service = imports.service;
-const Utils = imports.utils;
-const GeoJSONStyle = imports.geoJSONStyle;
-const MapView = imports.mapView;
+import {BoundingBox} from './boundingBox.js';
+import * as Geojsonvt from './geojsonvt/geojsonvt.js';
+import {Location} from './location.js';
+import {Place} from './place.js';
+import {PlaceMarker} from './placeMarker.js';
+import * as Service from './service.js';
+import * as Utils from './utils.js';
+import {GeoJSONStyle} from './geoJSONStyle.js';
+import {MapView} from './mapView.js';
 
 const TileFeature = { POINT: 1,
                       LINESTRING: 2,
                       POLYGON: 3 };
 
-var GeoJSONSource = GObject.registerClass(
-class GeoJSONSource extends Champlain.TileSource {
+export class GeoJSONSource extends Champlain.TileSource {
 
-    _init(params) {
-        super._init();
+    constructor(params) {
+        super();
 
         this._mapView = params.mapView;
         this._markerLayer = params.markerLayer;
-        this._bbox = new BoundingBox.BoundingBox();
+        this._bbox = new BoundingBox();
         this._tileSize = Service.getService().tiles.street.tile_size;
     }
 
@@ -129,16 +128,12 @@ class GeoJSONSource extends Champlain.TileSource {
         this._bbox.extend(coordinates[1],
                           coordinates[0]);
 
-        let location = new Location.Location({
-            latitude: coordinates[1],
-            longitude: coordinates[0]
-        });
+        let location = new Location({ latitude: coordinates[1],
+                                      longitude: coordinates[0] });
 
-        let place = new Place.Place({ name: name,
-                                      store: false,
-                                      location: location });
-        let placeMarker = new PlaceMarker.PlaceMarker({ place: place,
-                                                        mapView: this._mapView });
+        let place = new Place({ name: name, store: false, location: location });
+        let placeMarker = new PlaceMarker({ place: place,
+                                            mapView: this._mapView });
         this._markerLayer.add_marker(placeMarker);
     }
 
@@ -240,7 +235,7 @@ class GeoJSONSource extends Champlain.TileSource {
                 if (feature.type === TileFeature.POINT)
                     return;
 
-                let geoJSONStyleObj = GeoJSONStyle.GeoJSONStyle.parseSimpleStyle(feature.tags);
+                let geoJSONStyleObj = GeoJSONStyle.parseSimpleStyle(feature.tags);
 
                 feature.geometry.forEach((geometry) => {
                     let first = true;
@@ -278,4 +273,6 @@ class GeoJSONSource extends Champlain.TileSource {
 
         content.invalidate();
     }
-});
+}
+
+GObject.registerClass(GeoJSONSource);
diff --git a/src/geoJSONStyle.js b/src/geoJSONStyle.js
index 2cfd7162..15c1f734 100644
--- a/src/geoJSONStyle.js
+++ b/src/geoJSONStyle.js
@@ -21,7 +21,16 @@
 const DEFAULT_LINE_WIDTH = 5;
 const DEFAULT_COLOR = '69B1FF';
 
-var GeoJSONStyle = class GeoJSONStyle {
+export class GeoJSONStyle {
+
+    static parseSimpleStyle(tags) {
+        return new GeoJSONStyle({ alpha: tags['stroke-opacity'],
+                                  fillAlpha: tags['fill-opacity'],
+                                  color: tags['stroke'],
+                                  fillColor: tags['fill'],
+                                  lineWidth: tags['stroke-width'] });
+    }
+
     constructor(params) {
         if (params.lineWidth || params.lineWidth === 0)
             this.lineWidth = params.lineWidth;
@@ -76,12 +85,4 @@ var GeoJSONStyle = class GeoJSONStyle {
 
         return color;
     }
-};
-
-GeoJSONStyle.parseSimpleStyle = function(tags) {
-    return  new GeoJSONStyle({ alpha: tags['stroke-opacity'],
-                               fillAlpha: tags['fill-opacity'],
-                               color: tags['stroke'],
-                               fillColor: tags['fill'],
-                               lineWidth: tags['stroke-width'] });
 }
diff --git a/src/geoclue.js b/src/geoclue.js
index af127355..3efee83d 100644
--- a/src/geoclue.js
+++ b/src/geoclue.js
@@ -19,38 +19,23 @@
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const GObject = imports.gi.GObject;
-const GClue = imports.gi.Geoclue;
-const Gio = imports.gi.Gio;
+import GObject from 'gi://GObject';
+import GClue from 'gi://Geoclue';
+import Gio from 'gi://Gio';
 const Mainloop = imports.mainloop;
 
-const Place = imports.place;
-const Location = imports.location;
-const Settings = imports.settings;
-const Utils = imports.utils;
+import {Place} from './place.js';
+import {Location} from './location.js';
+import * as Utils from './utils.js';
 
-var State = {
+export const State = {
     INITIAL: 0,
     ON: 1,
     DENIED: 2,
     FAILED: 3
 };
 
-var Geoclue = GObject.registerClass({
-    Signals: {
-        'location-changed': { }
-    },
-    Properties: {
-        'state': GObject.ParamSpec.int('state',
-                                       '',
-                                       '',
-                                       GObject.ParamFlags.READABLE |
-                                       GObject.ParamFlags.WRITABLE,
-                                       State.INITIAL,
-                                       State.FAILED,
-                                       State.INITIAL)
-    },
-}, class Geoclue extends GObject.Object {
+export class Geoclue extends GObject.Object {
 
     set state(s) {
         this._state = s;
@@ -61,8 +46,8 @@ var Geoclue = GObject.registerClass({
         return this._state;
     }
 
-    _init() {
-        super._init();
+    constructor() {
+        super();
         this.place = null;
         this._state = State.INITIAL;
 
@@ -107,7 +92,7 @@ var Geoclue = GObject.registerClass({
 
     _onLocationNotify(simple) {
         let geoclueLocation = simple.get_location();
-        let location = new Location.Location({
+        let location = new Location({
             latitude: geoclueLocation.latitude,
             longitude: geoclueLocation.longitude,
             accuracy: geoclueLocation.accuracy,
@@ -119,8 +104,8 @@ var Geoclue = GObject.registerClass({
 
     _updateLocation(location) {
         if (!this.place)
-            this.place = new Place.Place({ name: _("Current Location"),
-                                           isCurrentLocation: true });
+            this.place = new Place({ name: _("Current Location"),
+                                     isCurrentLocation: true });
 
         this.place.location = location;
         this.emit('location-changed');
@@ -128,4 +113,20 @@ var Geoclue = GObject.registerClass({
                     " (" + location.latitude + ", " + location.longitude +
                     ", accuracy = " + location.accuracy + " m)");
     }
-});
+}
+
+GObject.registerClass({
+    Signals: {
+        'location-changed': { }
+    },
+    Properties: {
+        'state': GObject.ParamSpec.int('state',
+                                       '',
+                                       '',
+                                       GObject.ParamFlags.READABLE |
+                                       GObject.ParamFlags.WRITABLE,
+                                       State.INITIAL,
+                                       State.FAILED,
+                                       State.INITIAL)
+    },
+}, Geoclue);
diff --git a/src/geocode.js b/src/geocode.js
index 7623684a..3915d36a 100644
--- a/src/geocode.js
+++ b/src/geocode.js
@@ -19,18 +19,18 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Service = imports.service;
-const GraphHopperGeocode = imports.graphHopperGeocode;
-const PhotonGeocode = imports.photonGeocode;
+import * as Service from './service.js';
+import {GraphHopperGeocode} from './graphHopperGeocode.js';
+import {PhotonGeocode} from './photonGeocode.js';
 
 var _geocoder = null;
 
-function getGeocoder() {
+export function getGeocoder() {
     if (!_geocoder) {
         if (Service.getService().photonGeocode)
-            _geocoder = new PhotonGeocode.PhotonGeocode();
+            _geocoder = new PhotonGeocode();
         else
-            _geocoder = new GraphHopperGeocode.GraphHopperGeocode();
+            _geocoder = new GraphHopperGeocode();
     }
 
     return _geocoder;
diff --git a/src/geojson-vt/clip.js b/src/geojson-vt/clip.js
index cad7a21e..db5a1336 100644
--- a/src/geojson-vt/clip.js
+++ b/src/geojson-vt/clip.js
@@ -7,7 +7,7 @@
  *     |        |
  */
 
-function clip(features, scale, k1, k2, axis, intersect, minAll, maxAll) {
+export function clip(features, scale, k1, k2, axis, intersect, minAll, maxAll) {
 
     k1 /= scale;
     k2 /= scale;
diff --git a/src/geojson-vt/convert.js b/src/geojson-vt/convert.js
index eda26c7d..ebbe6a24 100644
--- a/src/geojson-vt/convert.js
+++ b/src/geojson-vt/convert.js
@@ -1,10 +1,10 @@
 'use strict';
 
-const simplify = imports.geojsonvt.simplify.simplify;
+import {simplify} from './simplify.js';
 
 // converts GeoJSON feature into an intermediate projected JSON vector format with simplification data
 
-function convert(data, tolerance) {
+export function convert(data, tolerance) {
     var features = [];
 
     if (data.type === 'FeatureCollection') {
diff --git a/src/geojson-vt/index.js b/src/geojson-vt/index.js
index bd0c6e59..c0d6785f 100644
--- a/src/geojson-vt/index.js
+++ b/src/geojson-vt/index.js
@@ -1,13 +1,16 @@
 'use strict';
 
-const convert = imports.geojsonvt.convert.convert;
-const transform = { tile: imports.geojsonvt.transform.transformTile,
-                    point: imports.geojsonvt.transform.transformPoint };
-const clip = imports.geojsonvt.clip.clip;
-const createTile = imports.geojsonvt.tile.createTile;
-const wrap = imports.geojsonvt.wrap.wrap;
-
-function geojsonvt(data, options) {
+import {convert} from './convert.js';
+import {transformTile, transformPoint} from './transform.js';
+
+import {clip} from './clip.js';
+import {createTile} from './tile.js';
+import {wrap} from './wrap.js';
+
+const transform = { tile: transformTile,
+                    point: transformPoint };
+
+export function geojsonvt(data, options) {
     return new GeoJSONVT(data, options);
 }
 
diff --git a/src/geojson-vt/simplify.js b/src/geojson-vt/simplify.js
index 2e55972e..6fe10541 100644
--- a/src/geojson-vt/simplify.js
+++ b/src/geojson-vt/simplify.js
@@ -2,7 +2,7 @@
 
 // calculate simplification data using optimized Douglas-Peucker algorithm
 
-function simplify(points, tolerance) {
+export function simplify(points, tolerance) {
 
     var sqTolerance = tolerance * tolerance,
         len = points.length,
diff --git a/src/geojson-vt/tile.js b/src/geojson-vt/tile.js
index 764d5385..d1f5ea3b 100644
--- a/src/geojson-vt/tile.js
+++ b/src/geojson-vt/tile.js
@@ -1,6 +1,6 @@
 'use strict';
 
-function createTile(features, z2, tx, ty, tolerance, noSimplify) {
+export function createTile(features, z2, tx, ty, tolerance, noSimplify) {
     var tile = {
         features: [],
         numPoints: 0,
diff --git a/src/geojson-vt/transform.js b/src/geojson-vt/transform.js
index fe93e947..3cf1a7cd 100644
--- a/src/geojson-vt/transform.js
+++ b/src/geojson-vt/transform.js
@@ -2,7 +2,7 @@
 
 // Transforms the coordinates of each feature in the given tile from
 // mercator-projected space into (extent x extent) tile space.
-function transformTile(tile, extent) {
+export function transformTile(tile, extent) {
     if (tile.transformed) return tile;
 
     var z2 = tile.z2,
@@ -31,7 +31,7 @@ function transformTile(tile, extent) {
     return tile;
 }
 
-function transformPoint(p, extent, z2, tx, ty) {
+export function transformPoint(p, extent, z2, tx, ty) {
     var x = Math.round(extent * (p[0] * z2 - tx)),
         y = Math.round(extent * (p[1] * z2 - ty));
     return [x, y];
diff --git a/src/geojson-vt/wrap.js b/src/geojson-vt/wrap.js
index 7d9b243a..feeec939 100644
--- a/src/geojson-vt/wrap.js
+++ b/src/geojson-vt/wrap.js
@@ -1,8 +1,8 @@
 'use strict';
 
-const clip = imports.geojsonvt.clip.clip;
+import {clip} from './clip.js';
 
-function wrap(features, buffer, intersectX) {
+export function wrap(features, buffer, intersectX) {
     var merged = features,
         left  = clip(features, 1, -1 - buffer, buffer,     0, intersectX, -1, 2), // left world copy
         right = clip(features, 1,  1 - buffer, 2 + buffer, 0, intersectX, -1, 2); // right world copy
diff --git a/src/gfx.js b/src/gfx.js
index 8f6ce6a4..bde7bc8f 100644
--- a/src/gfx.js
+++ b/src/gfx.js
@@ -19,7 +19,7 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Color = imports.color;
+import * as Color from './color.js';
 
 /**
  * Draws a colored badged with rounded corners and an optional outline.
@@ -33,7 +33,7 @@ const Color = imports.color;
  * width: The width to draw the badge
  * height: The height to draw the badge
  */
-function drawColoredBagde(cr, bgColor, outlineColor, x, y, width, height) {
+export function drawColoredBagde(cr, bgColor, outlineColor, x, y, width, height) {
     let bgRed = Color.parseColor(bgColor, 0);
     let bgGreen = Color.parseColor(bgColor, 1);
     let bgBlue = Color.parseColor(bgColor, 2);
diff --git a/src/gpxShapeLayer.js b/src/gpxShapeLayer.js
index e3a23b99..d684e2ce 100644
--- a/src/gpxShapeLayer.js
+++ b/src/gpxShapeLayer.js
@@ -17,24 +17,28 @@
  * Author: Hashem Nasarat <hashem riseup net>
  */
 
-const GObject = imports.gi.GObject;
+import GObject from 'gi://GObject';
 
-const GeoJSONSource = imports.geoJSONSource;
-const ShapeLayer = imports.shapeLayer;
-const Utils = imports.utils;
-const Togeojson = imports.togeojson.togeojson;
-const Domparser = imports.xmldom.domparser;
+import {GeoJSONSource} from './geoJSONSource.js';
+import {ShapeLayer} from './shapeLayer.js';
+import * as Utils from './utils.js';
+import * as Togeojson from './togeojson/togeojson.js';
+import * as Domparser from './xmldom/domparser.js';
 
-var GpxShapeLayer = GObject.registerClass(
-class GpxShapeLayer extends ShapeLayer.ShapeLayer {
+export class GpxShapeLayer extends ShapeLayer {
 
-    _init(params) {
-        super._init(params);
+    static mimeTypes = ['application/gpx+xml' ];
+    static displayName = 'GPX';
 
-        this._mapSource = new GeoJSONSource.GeoJSONSource({
-            mapView: this._mapView,
-            markerLayer: this._markerLayer
-        });
+    static createInstance(params) {
+        return new GpxShapeLayer(params);
+    };
+
+    constructor(params) {
+        super(params);
+
+        this._mapSource = new GeoJSONSource({ mapView: this._mapView,
+                                              markerLayer: this._markerLayer });
     }
 
     _parseContent() {
@@ -43,10 +47,6 @@ class GpxShapeLayer extends ShapeLayer.ShapeLayer {
         let json = Togeojson.toGeoJSON.gpx(parser.parseFromString(s));
         this._mapSource.parse(json);
     }
-});
+}
 
-GpxShapeLayer.mimeTypes = ['application/gpx+xml' ];
-GpxShapeLayer.displayName = 'GPX';
-GpxShapeLayer.createInstance = function(params) {
-    return new GpxShapeLayer(params);
-};
+GObject.registerClass(GpxShapeLayer);
diff --git a/src/graphHopper.js b/src/graphHopper.js
index 831e6da6..f6115fc7 100644
--- a/src/graphHopper.js
+++ b/src/graphHopper.js
@@ -19,22 +19,22 @@
  * Author: Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const GLib = imports.gi.GLib;
+import GLib from 'gi://GLib';
 const Mainloop = imports.mainloop;
-const Soup = imports.gi.Soup;
+import Soup from 'gi://Soup';
 
-const BoundingBox = imports.boundingBox;
-const EPAF = imports.epaf;
-const HTTP = imports.http;
-const Route = imports.route;
-const RouteQuery = imports.routeQuery;
-const Utils = imports.utils;
+import {BoundingBox} from './boundingBox.js';
+import * as EPAF from './epaf.js';
+import {Query} from './http.js';
+import {TurnPoint, Route} from './route.js';
+import {RouteQuery} from './routeQuery.js';
+import * as Utils from './utils.js';
 
 /**
  * Directional sign from the GraphHopper API.
  * https://github.com/graphhopper/graphhopper/blob/master/docs/web/api-doc.md
  */
-var Sign = {
+const Sign = {
     UTURN: -98,
     UTURN_LEFT: -8,
     KEEP_LEFT: -7,
@@ -53,7 +53,7 @@ var Sign = {
     UTURN_RIGHT: 8
 }
 
-var GraphHopper = class GraphHopper {
+export class GraphHopper {
 
     get route() {
         return this._route;
@@ -64,7 +64,7 @@ var GraphHopper = class GraphHopper {
         this._key     = "VCIHrHj0pDKb8INLpT4s5hVadNmJ1Q3vi0J4nJYP";
         this._baseURL = "https://graphhopper.com/api/1/route?";;
         this._locale  = GLib.get_language_names()[0];
-        this._route   = new Route.Route();
+        this._route   = new Route();
         this.storedRoute = null;
         this._query = params.query;
     }
@@ -146,13 +146,12 @@ var GraphHopper = class GraphHopper {
             return [point.place.location.latitude, point.place.location.longitude].join(',');
         });
         let vehicle = RouteQuery.Transportation.toString(transportation);
-        let query = new HTTP.Query({ type:    'json',
-                                     key:     this._key,
-                                     vehicle: vehicle,
-                                     locale:  this._locale,
-                                     point:   locations,
-                                     debug:   Utils.debugEnabled
-                                   });
+        let query = new Query({ type:    'json',
+                                key:     this._key,
+                                vehicle: vehicle,
+                                locale:  this._locale,
+                                point:   locations,
+                                debug:   Utils.debugEnabled });
         let url = this._baseURL + query.toString();
         Utils.debug("Sending route request to: " + url);
         return url;
@@ -189,7 +188,7 @@ var GraphHopper = class GraphHopper {
     _createRoute(route) {
         let path       = EPAF.decode(route.points);
         let turnPoints = this._createTurnPoints(path, route.instructions);
-        let bbox       = new BoundingBox.BoundingBox();
+        let bbox       = new BoundingBox();
 
         // GH does lonlat-order
         bbox.extend(route.bbox[1], route.bbox[0]);
@@ -204,9 +203,9 @@ var GraphHopper = class GraphHopper {
 
     _createTurnPoints(path, instructions) {
         let via = 0;
-        let startPoint = new Route.TurnPoint({
+        let startPoint = new TurnPoint({
             coordinate:  path[0],
-            type:        Route.TurnPointType.START,
+            type:        TurnPoint.Type.START,
             distance:    0,
             instruction: _("Start!"),
             time:        0,
@@ -215,12 +214,12 @@ var GraphHopper = class GraphHopper {
         let rest = this._foldInstructions(instructions).map((instr) => {
             let type = this._createTurnPointType(instr.sign);
             let text = instr.text;
-            if (type === Route.TurnPointType.VIA) {
+            if (type === TurnPoint.Type.VIA) {
                 via++;
                 let viaPlace = this._query.filledPoints[via].place;
                 text = viaPlace.name || instr.text;
             }
-            return new Route.TurnPoint({
+            return new TurnPoint({
                 coordinate:  path[instr.interval[0]],
                 type:        type,
                 distance:    instr.distance,
@@ -259,23 +258,23 @@ var GraphHopper = class GraphHopper {
 
     _createTurnPointType(sign) {
         switch (sign) {
-            case Sign.UTURN:              return Route.TurnPointType.UTURN;
-            case Sign.UTURN_LEFT:         return Route.TurnPointType.UTURN_LEFT;
-            case Sign.KEEP_LEFT:          return Route.TurnPointType.KEEP_LEFT;
-            case Sign.LEAVE_ROUNDABOUT:   return Route.TurnPointType.LEAVE_ROUNDABOUT;
-            case Sign.TURN_SHARP_LEFT:    return Route.TurnPointType.SHARP_LEFT;
-            case Sign.TURN_LEFT:          return Route.TurnPointType.LEFT;
-            case Sign.TURN_SLIGHT_LEFT:   return Route.TurnPointType.SLIGHT_LEFT;
-            case Sign.CONTINUE_ON_STREET: return Route.TurnPointType.CONTINUE;
-            case Sign.TURN_SLIGHT_RIGHT:  return Route.TurnPointType.SLIGHT_RIGHT;
-            case Sign.TURN_RIGHT:         return Route.TurnPointType.RIGHT;
-            case Sign.TURN_SHARP_RIGHT:   return Route.TurnPointType.SHARP_RIGHT;
-            case Sign.FINISH:             return Route.TurnPointType.END;
-            case Sign.REACHED_VIA:        return Route.TurnPointType.VIA;
-            case Sign.USE_ROUNDABOUT:     return Route.TurnPointType.ROUNDABOUT;
-            case Sign.KEEP_RIGHT:         return Route.TurnPointType.KEEP_RIGHT;
-            case Sign.UTURN_RIGHT:        return Route.TurnPointType.UTURN_RIGHT;
+            case Sign.UTURN:              return TurnPoint.Type.UTURN;
+            case Sign.UTURN_LEFT:         return TurnPoint.Type.UTURN_LEFT;
+            case Sign.KEEP_LEFT:          return TurnPoint.Type.KEEP_LEFT;
+            case Sign.LEAVE_ROUNDABOUT:   return TurnPoint.Type.LEAVE_ROUNDABOUT;
+            case Sign.TURN_SHARP_LEFT:    return TurnPoint.Type.SHARP_LEFT;
+            case Sign.TURN_LEFT:          return TurnPoint.Type.LEFT;
+            case Sign.TURN_SLIGHT_LEFT:   return TurnPoint.Type.SLIGHT_LEFT;
+            case Sign.CONTINUE_ON_STREET: return TurnPoint.Type.CONTINUE;
+            case Sign.TURN_SLIGHT_RIGHT:  return TurnPoint.Type.SLIGHT_RIGHT;
+            case Sign.TURN_RIGHT:         return TurnPoint.Type.RIGHT;
+            case Sign.TURN_SHARP_RIGHT:   return TurnPoint.Type.SHARP_RIGHT;
+            case Sign.FINISH:             return TurnPoint.Type.END;
+            case Sign.REACHED_VIA:        return TurnPoint.Type.VIA;
+            case Sign.USE_ROUNDABOUT:     return TurnPoint.Type.ROUNDABOUT;
+            case Sign.KEEP_RIGHT:         return TurnPoint.Type.KEEP_RIGHT;
+            case Sign.UTURN_RIGHT:        return TurnPoint.Type.UTURN_RIGHT;
             default: return undefined;
         }
     }
-};
+}
diff --git a/src/graphHopperGeocode.js b/src/graphHopperGeocode.js
index 975cde2e..b74142c3 100644
--- a/src/graphHopperGeocode.js
+++ b/src/graphHopperGeocode.js
@@ -21,19 +21,19 @@
 
 const Format = imports.format;
 
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
-const Application = imports.application;
-const HTTP = imports.http;
-const PhotonParser = imports.photonParser;
-const Service = imports.service;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import * as HTTP from './http.js';
+import * as PhotonParser from './photonParser.js';
+import * as Service from './service.js';
+import * as Utils from './utils.js';
 
 // HTTP session timeout (in seconds)
 const TIMEOUT = 5;
 
-var GraphHopperGeocode = class {
+export class GraphHopperGeocode {
     constructor() {
         this._session =
             new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version,
diff --git a/src/graphHopperTransit.js b/src/graphHopperTransit.js
index 7fa927e9..e60aff80 100644
--- a/src/graphHopperTransit.js
+++ b/src/graphHopperTransit.js
@@ -25,19 +25,19 @@
  * routing for walking legs
  */
 
-const Champlain = imports.gi.Champlain;
+import Champlain from 'gi://Champlain';
 
-const Application = imports.application;
-const Location = imports.location;
-const Place = imports.place;
-const RouteQuery = imports.routeQuery;
-const TransitPlan = imports.transitPlan;
+import {Application} from './application.js';
+import {Location} from './location.js';
+import {Place} from './place.js';
+import {RouteQuery, QueryPoint} from './routeQuery.js';
+import {Leg} from './transitPlan.js';
 
 /* Creates a new walking leg given start and end places, and a route
  * obtained from GraphHopper. If the route is undefined (which happens if
  * GraphHopper failed to obtain a walking route, approximate it with a
  * straight line. */
-function createWalkingLeg(from, to, fromName, toName, route) {
+export function createWalkingLeg(from, to, fromName, toName, route) {
     let fromLocation = from.place.location;
     let toLocation = to.place.location;
     let fromCoordinate = [fromLocation.latitude, fromLocation.longitude];
@@ -51,15 +51,15 @@ function createWalkingLeg(from, to, fromName, toName, route) {
     let duration = route ? route.time / 1000 : distance;
     let walkingInstructions = route ? route.turnPoints : null;
 
-    return new TransitPlan.Leg({ fromCoordinate: fromCoordinate,
-                                 toCoordinate: toCoordinate,
-                                 from: fromName,
-                                 to: toName,
-                                 isTransit: false,
-                                 polyline: polyline,
-                                 duration: duration,
-                                 distance: distance,
-                                 walkingInstructions: walkingInstructions });
+    return new Leg({ fromCoordinate: fromCoordinate,
+                     toCoordinate: toCoordinate,
+                     from: fromName,
+                     to: toName,
+                     isTransit: false,
+                     polyline: polyline,
+                     duration: duration,
+                     distance: distance,
+                     walkingInstructions: walkingInstructions });
 }
 
 // create a straight-line "as the crow flies" polyline between two places
@@ -75,7 +75,7 @@ var _walkingRoutes = [];
 /* fetches walking route and stores the route for the given coordinate
  * pair to avoid requesting the same route over and over from GraphHopper
  */
-function fetchWalkingRoute(points, callback) {
+export function fetchWalkingRoute(points, callback) {
     let index = points[0].place.location.latitude + ',' +
                 points[0].place.location.longitude + ';' +
                 points[1].place.location.latitude + ',' +
@@ -95,12 +95,12 @@ function fetchWalkingRoute(points, callback) {
 }
 
 // create a query point from a bare coordinate (lat, lon pair)
-function createQueryPointForCoord(coord) {
-    let location = new Location.Location({ latitude: coord[0],
-                                           longitude: coord[1],
-                                           accuracy: 0 });
-    let place = new Place.Place({ location: location });
-    let point = new RouteQuery.QueryPoint();
+export function createQueryPointForCoord(coord) {
+    let location = new Location({ latitude: coord[0],
+                                  longitude: coord[1],
+                                  accuracy: 0 });
+    let place = new Place({ location: location });
+    let point = new QueryPoint();
 
     point.place = place;
     return point;
@@ -111,7 +111,7 @@ function createQueryPointForCoord(coord) {
  * Intended for use by transit plugins where the source API doesn't give
  * full walking turn-by-turn routing
  */
-function addWalkingToItineraries(itineraries, callback) {
+export function addWalkingToItineraries(itineraries, callback) {
     _addWalkingToItinerariesRecursive(itineraries, 0, callback);
 }
 
diff --git a/src/headerBar.js b/src/headerBar.js
index cbd74274..b023b81d 100644
--- a/src/headerBar.js
+++ b/src/headerBar.js
@@ -20,62 +20,56 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const FavoritesPopover = imports.favoritesPopover;
-const LayersPopover = imports.layersPopover;
-const MapView = imports.mapView;
+import {FavoritesPopover} from './favoritesPopover.js';
+import {LayersPopover} from './layersPopover.js';
+import {MapView} from './mapView.js';
 
-var HeaderBarLeft = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/headerbar-left.ui',
-    InternalChildren: [ 'layersButton' ]
-}, class HeaderBarLeft extends Gtk.Box {
-    _init(params) {
-        this._application = params.application;
-        delete params.application;
-
-        this._mapView = params.mapView;
+export class HeaderBarLeft extends Gtk.Box {
+    constructor(params) {
+        let mapView = params.mapView;
         delete params.mapView;
 
-        super._init(params);
+        super(params);
 
-        this._layersPopover = new LayersPopover.LayersPopover({
-            mapView: this._mapView
-        });
+        this._layersPopover = new LayersPopover({ mapView: mapView });
         this._layersButton.popover = this._layersPopover;
     }
 
     popdownLayersPopover() {
         this._layersPopover.popdown();
     }
-});
+}
 
-var HeaderBarRight = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/headerbar-right.ui',
-    InternalChildren: [ 'toggleSidebarButton',
-                        'favoritesButton',
-                        'printRouteButton' ]
-}, class HeaderBarRight extends Gtk.Box {
-    _init(params) {
-        this._application = params.application;
-        delete params.application;
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/headerbar-left.ui',
+    InternalChildren: [ 'layersButton' ]
+}, HeaderBarLeft);
 
-        this._mapView = params.mapView;
+export class HeaderBarRight extends Gtk.Box {
+    constructor(params) {
+        let mapView = params.mapView;
         delete params.mapView;
 
-        super._init(params);
+        super(params);
 
-        this._favoritesButton.popover = new FavoritesPopover.FavoritesPopover({
-            mapView: this._mapView
-        });
+        this._favoritesButton.popover = new FavoritesPopover({ mapView: mapView });
         let favoritesPopover = this._favoritesButton.popover;
         this._favoritesButton.sensitive = favoritesPopover.rows > 0;
         favoritesPopover.connect('notify::rows', () => {
             this._favoritesButton.sensitive = favoritesPopover.rows > 0;
         });
 
-        this._mapView.bind_property('routeShowing', this._printRouteButton,
-                                    'visible', GObject.BindingFlags.DEFAULT);
+        mapView.bind_property('routeShowing', this._printRouteButton,
+                              'visible', GObject.BindingFlags.DEFAULT);
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/headerbar-right.ui',
+    InternalChildren: [ 'toggleSidebarButton',
+                        'favoritesButton',
+                        'printRouteButton' ]
+}, HeaderBarRight);
diff --git a/src/http.js b/src/http.js
index 8d853fee..ee8e65dc 100644
--- a/src/http.js
+++ b/src/http.js
@@ -19,7 +19,7 @@
  * Author: Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const Soup = imports.gi.Soup;
+import Soup from 'gi://Soup';
 
 function encode(data) {
     if(data === null)
@@ -28,7 +28,7 @@ function encode(data) {
     return Soup.URI.encode(data.toString(), '&');
 }
 
-var Query = class Query {
+export class Query {
 
     constructor(obj) {
         this._query = {};
@@ -73,4 +73,4 @@ var Query = class Query {
         }
         return vars.join('&');
     }
-};
+}
diff --git a/src/hvt.js b/src/hvt.js
index 810b1ad4..a2dbcb10 100644
--- a/src/hvt.js
+++ b/src/hvt.js
@@ -30,185 +30,185 @@
  */
 
 // rail services
-var RAILWAY_SERVICE = 100;
-var HIGH_SPEED_RAIL_SERVICE = 101;
-var LONG_DISTANCE_TRAINS = 102;
-var INTER_REGIONAL_RAIL_SERVICE = 103;
-var CAR_TRANSPORT_RAIL_SERVICE = 104;
-var SLEEPER_RAIL_SERVICE = 105;
-var REGIONAL_RAIL_SERVICE = 106;
-var TOURIST_RAILWAY_SERVICE = 107;
-var RAIL_SHUTTLE = 108;
-var SUBURBAN_RAILWAY = 109;
-var REPLACEMENT_RAIL_SERVICE = 110;
-var SPECIAL_RAIL_SERVICE = 111;
-var LORRY_TRANSPORT_RAIL_SERVICE = 112;
-var ALL_RAIL_SERVICES = 113;
-var CROSS_COUNTRY_RAIL_SERVICE = 114;
-var VEHICLE_TRANSPORT_RAIL_SERVICE = 115;
-var RACK_AND_PINION_RAILWAY = 116;
-var ADDITIONAL_RAIL_SERVICE = 117;
-var LAST_RAIL_SERVICE = ADDITIONAL_RAIL_SERVICE;
+export const RAILWAY_SERVICE = 100;
+export const HIGH_SPEED_RAIL_SERVICE = 101;
+export const LONG_DISTANCE_TRAINS = 102;
+export const INTER_REGIONAL_RAIL_SERVICE = 103;
+export const CAR_TRANSPORT_RAIL_SERVICE = 104;
+export const SLEEPER_RAIL_SERVICE = 105;
+export const REGIONAL_RAIL_SERVICE = 106;
+export const TOURIST_RAILWAY_SERVICE = 107;
+export const RAIL_SHUTTLE = 108;
+export const SUBURBAN_RAILWAY = 109;
+export const REPLACEMENT_RAIL_SERVICE = 110;
+export const SPECIAL_RAIL_SERVICE = 111;
+export const LORRY_TRANSPORT_RAIL_SERVICE = 112;
+export const ALL_RAIL_SERVICES = 113;
+export const CROSS_COUNTRY_RAIL_SERVICE = 114;
+export const VEHICLE_TRANSPORT_RAIL_SERVICE = 115;
+export const RACK_AND_PINION_RAILWAY = 116;
+export const ADDITIONAL_RAIL_SERVICE = 117;
+export const LAST_RAIL_SERVICE = ADDITIONAL_RAIL_SERVICE;
 
 // coach services
-var COACH_SERVICE = 200;
-var INTERNATIONAL_COACH_SERVICE = 201;
-var NATIONAL_COACH_SERVICE = 202;
-var SHUTTLE_COACH_SERVICE = 203;
-var REGIONAL_COACH_SERVICE = 204;
-var SPECIAL_COACH_SERVICE = 205;
-var SIGHTSEEING_COACH_SERVICE = 206;
-var TOURIST_COACH_SERVICE = 207;
-var COMMUTER_COACH_SERVICE = 208;
-var ALL_COACH_SERVICES = 209;
-var LAST_COACH_SERVICE = ALL_COACH_SERVICES;
+export const COACH_SERVICE = 200;
+export const INTERNATIONAL_COACH_SERVICE = 201;
+export const NATIONAL_COACH_SERVICE = 202;
+export const SHUTTLE_COACH_SERVICE = 203;
+export const REGIONAL_COACH_SERVICE = 204;
+export const SPECIAL_COACH_SERVICE = 205;
+export const SIGHTSEEING_COACH_SERVICE = 206;
+export const TOURIST_COACH_SERVICE = 207;
+export const COMMUTER_COACH_SERVICE = 208;
+export const ALL_COACH_SERVICES = 209;
+export const LAST_COACH_SERVICE = ALL_COACH_SERVICES;
 
 /// suburban railway services
-var SUBURBAN_RAILWAY_SERVICE = 300;
+export const SUBURBAN_RAILWAY_SERVICE = 300;
 
 // urban railway services
-var URBAN_RAILWAY_SERVICE = 400;
-var URBAN_METRO_SERVICE = 401;
-var URBAN_UNDERGROUND_SERVICE = 402;
+export const URBAN_RAILWAY_SERVICE = 400;
+export const URBAN_METRO_SERVICE = 401;
+export const URBAN_UNDERGROUND_SERVICE = 402;
 // this constant has the same name as 400 in the specification
-var URBAN_RAILWAY_SERVICE_2 = 403;
-var ALL_URBAN_RAILWAY_SERVICES = 404;
-var MONORAIL = 405;
-var LAST_URBAN_RAILWAY_SERVICE = MONORAIL;
+export const URBAN_RAILWAY_SERVICE_2 = 403;
+export const ALL_URBAN_RAILWAY_SERVICES = 404;
+export const MONORAIL = 405;
+export const LAST_URBAN_RAILWAY_SERVICE = MONORAIL;
 
 // metro services
-var METRO_SERVICE = 500;
+export const METRO_SERVICE = 500;
 
 // underground services
-var UNDERGROUND_SERVICE = 600;
+export const UNDERGROUND_SERVICE = 600;
 
 // bus services
-var BUS_SERVICE = 700;
-var REGIONAL_BUS_SERVICE = 701;
-var EXPRESS_BUS_SERVICE = 702;
-var STOPPING_BUS_SERVICE = 703;
-var LOCAL_BUS_SERVICE = 704;
-var NIGHT_BUS_SERVICE = 705;
-var POST_BUS_SERVICE = 706;
-var SPECIAL_NEEDS_BUS_SERVICE = 707;
-var MOBILITY_BUS_SERVICE = 708;
-var MOBILITY_BUS_SERVICE_FOR_REGISTERED_DISABLED = 709;
-var SIGHTSEEING_BUS = 710;
-var SHUTTLE_BUS = 711;
-var SCHOOL_BUS = 712;
-var SCHOOL_AND_PUBLIC_SERVICE_BUS_SERVICE = 713;
-var RAIL_REPLACEMENT_BUS_SERVICE = 714;
-var DEMAND_AND_RESPONSE_BUS_SERVICE = 715;
-var ALL_BUS_SERVICES = 716;
-var LAST_BUS_SERVICE = ALL_BUS_SERVICES;
+export const BUS_SERVICE = 700;
+export const REGIONAL_BUS_SERVICE = 701;
+export const EXPRESS_BUS_SERVICE = 702;
+export const STOPPING_BUS_SERVICE = 703;
+export const LOCAL_BUS_SERVICE = 704;
+export const NIGHT_BUS_SERVICE = 705;
+export const POST_BUS_SERVICE = 706;
+export const SPECIAL_NEEDS_BUS_SERVICE = 707;
+export const MOBILITY_BUS_SERVICE = 708;
+export const MOBILITY_BUS_SERVICE_FOR_REGISTERED_DISABLED = 709;
+export const SIGHTSEEING_BUS = 710;
+export const SHUTTLE_BUS = 711;
+export const SCHOOL_BUS = 712;
+export const SCHOOL_AND_PUBLIC_SERVICE_BUS_SERVICE = 713;
+export const RAIL_REPLACEMENT_BUS_SERVICE = 714;
+export const DEMAND_AND_RESPONSE_BUS_SERVICE = 715;
+export const ALL_BUS_SERVICES = 716;
+export const LAST_BUS_SERVICE = ALL_BUS_SERVICES;
 
 // trolleybus services
-var TROLLEYBUS_SERVICE = 800;
+export const TROLLEYBUS_SERVICE = 800;
 
 // tram services
-var TRAM_SERVICE = 900;
-var CITY_TRAM_SERVICE = 901;
-var LOCAL_TRAM_SERVICE = 902;
-var REGIONAL_TRAM_SERVICE = 903;
-var SIGHTSEEING_TRAM_SERVICE = 904;
-var SHUTTLE_TRAM_SERVICE = 905;
-var ALL_TRAM_SERVICES = 906;
-var LAST_TRAM_SERVICE = ALL_TRAM_SERVICES;
+export const TRAM_SERVICE = 900;
+export const CITY_TRAM_SERVICE = 901;
+export const LOCAL_TRAM_SERVICE = 902;
+export const REGIONAL_TRAM_SERVICE = 903;
+export const SIGHTSEEING_TRAM_SERVICE = 904;
+export const SHUTTLE_TRAM_SERVICE = 905;
+export const ALL_TRAM_SERVICES = 906;
+export const LAST_TRAM_SERVICE = ALL_TRAM_SERVICES;
 
 // water transport services
-var WATER_TRANSPORT_SERVICE = 1000;
-var INTERNATIONAL_CAR_FERRY_SERVICE = 1001;
-var NATIONAL_CAR_FERRY_SERVICE = 1002;
-var REGIONAL_CAR_FERRY_SERVICE = 1003;
-var LOCAL_CAR_FERRY_SERVICE = 1004;
-var INTERNATIONAL_PASSENGER_FERRY_SERVICE = 1005;
-var NATIONAL_PASSENGER_FERRY_SERVICE = 1006;
-var REGIONAL_PASSENGER_FERRY_SERVICE = 1007;
-var LOCAL_PASSENGER_FERRY_SERVICE = 1008;
-var POST_BOAT_SERVICE = 1009;
-var TRAIN_FERRY_SERVICE = 1010;
-var ROAD_LINK_FERRY_SERVICE = 1011;
-var AIRPORT_LINK_FERRY_SERVICE = 1012;
-var CAR_HIGH_SPEED_FERRY_SERVICE = 1013;
-var PASSENGER_HIGH_SPEED_FERRY_SERVICE = 1014;
-var SIGHTSEEING_BOAT_SERVICE = 1015;
-var SCHOOL_BOAT = 1016;
-var CABLE_DRAWN_BOAT_SERVICE = 1017;
-var RIVER_BUS_SERVICE = 1018;
-var SCHEDULED_FERRY_SERVICE = 1019;
-var SHUTTLE_FERRY_SERVICE = 1020;
-var ALL_WATER_TRANSPORT_SERVICE = 1021;
-var LAST_WATER_TRANSPORT_SERVICE = ALL_WATER_TRANSPORT_SERVICE;
+export const WATER_TRANSPORT_SERVICE = 1000;
+export const INTERNATIONAL_CAR_FERRY_SERVICE = 1001;
+export const NATIONAL_CAR_FERRY_SERVICE = 1002;
+export const REGIONAL_CAR_FERRY_SERVICE = 1003;
+export const LOCAL_CAR_FERRY_SERVICE = 1004;
+export const INTERNATIONAL_PASSENGER_FERRY_SERVICE = 1005;
+export const NATIONAL_PASSENGER_FERRY_SERVICE = 1006;
+export const REGIONAL_PASSENGER_FERRY_SERVICE = 1007;
+export const LOCAL_PASSENGER_FERRY_SERVICE = 1008;
+export const POST_BOAT_SERVICE = 1009;
+export const TRAIN_FERRY_SERVICE = 1010;
+export const ROAD_LINK_FERRY_SERVICE = 1011;
+export const AIRPORT_LINK_FERRY_SERVICE = 1012;
+export const CAR_HIGH_SPEED_FERRY_SERVICE = 1013;
+export const PASSENGER_HIGH_SPEED_FERRY_SERVICE = 1014;
+export const SIGHTSEEING_BOAT_SERVICE = 1015;
+export const SCHOOL_BOAT = 1016;
+export const CABLE_DRAWN_BOAT_SERVICE = 1017;
+export const RIVER_BUS_SERVICE = 1018;
+export const SCHEDULED_FERRY_SERVICE = 1019;
+export const SHUTTLE_FERRY_SERVICE = 1020;
+export const ALL_WATER_TRANSPORT_SERVICE = 1021;
+export const LAST_WATER_TRANSPORT_SERVICE = ALL_WATER_TRANSPORT_SERVICE;
 
 // air service
-var AIR_SERVICE = 1100;
-var INTERNATIONAL_AIR_SERVICE = 1101;
-var DOMESTIC_AIR_SERVICE = 1102;
-var INTERCONTINENTAL_AIR_SERVICE = 1103;
-var DOMESTIC_SCHEDULED_AIR_SERVICE = 1104;
-var SHUTTLE_AIR_SERVICE = 1105;
-var INTERCONTINENTAL_CHARTER_AIR_SERVICE = 1106;
-var INTERNATIONAL_CHARTER_AIR_SERVICE = 1107;
-var ROUND_TRIP_CHARTER_AIR_SERVICE = 1108;
-var SIGHTSEEING_AIR_SERVICE = 1109;
-var HELICOPTER_AIR_SERVICE = 1110;
-var DOMESTIC_CHARTER_AIR_SERVICE = 1111;
-var SCHENGEN_AREA_AIR_SERVICE = 1112;
-var AIRSHIP_SERVICE = 1113;
-var ALL_AIR_SERVICES = 1114;
-var LAST_AIR_SERVICE = ALL_AIR_SERVICES;
+export const AIR_SERVICE = 1100;
+export const INTERNATIONAL_AIR_SERVICE = 1101;
+export const DOMESTIC_AIR_SERVICE = 1102;
+export const INTERCONTINENTAL_AIR_SERVICE = 1103;
+export const DOMESTIC_SCHEDULED_AIR_SERVICE = 1104;
+export const SHUTTLE_AIR_SERVICE = 1105;
+export const INTERCONTINENTAL_CHARTER_AIR_SERVICE = 1106;
+export const INTERNATIONAL_CHARTER_AIR_SERVICE = 1107;
+export const ROUND_TRIP_CHARTER_AIR_SERVICE = 1108;
+export const SIGHTSEEING_AIR_SERVICE = 1109;
+export const HELICOPTER_AIR_SERVICE = 1110;
+export const DOMESTIC_CHARTER_AIR_SERVICE = 1111;
+export const SCHENGEN_AREA_AIR_SERVICE = 1112;
+export const AIRSHIP_SERVICE = 1113;
+export const ALL_AIR_SERVICES = 1114;
+export const LAST_AIR_SERVICE = ALL_AIR_SERVICES;
 
 // ferry services
-var FERRY_SERVICE = 1200;
+export const FERRY_SERVICE = 1200;
 
 // telecabin services
-var TELECABIN_SERVICE = 1300;
-var TELECABIN_SERVICES = 1301;
+export const TELECABIN_SERVICE = 1300;
+export const TELECABIN_SERVICES = 1301;
 // renamed this to not be confused with the tram-like street level cable cars
-var TELECABIN_CABLE_CAR_SERVICE = 1302;
-var ELEVATOR_SERVICE = 1303;
-var CHAIR_LIFT_SERVICE = 1304;
-var DRAG_LIFT_SERVICE = 1305;
-var SMALL_TELECABIN_SERVICE = 1306;
-var ALL_TELECABIN_SERVICES = 1307;
-var LAST_TELECABIN_SERVICE = ALL_TELECABIN_SERVICES;
+export const TELECABIN_CABLE_CAR_SERVICE = 1302;
+export const ELEVATOR_SERVICE = 1303;
+export const CHAIR_LIFT_SERVICE = 1304;
+export const DRAG_LIFT_SERVICE = 1305;
+export const SMALL_TELECABIN_SERVICE = 1306;
+export const ALL_TELECABIN_SERVICES = 1307;
+export const LAST_TELECABIN_SERVICE = ALL_TELECABIN_SERVICES;
 
 // funicular services
-var FUNICULAR_SERVICE = 1400;
-var FUNICULAR_SERVICE_2 = 1401;
-var ALL_FUNICULAR_SERVICES = 1402;
-var LAST_FUNICULAR_SERVICE = ALL_FUNICULAR_SERVICES;
+export const FUNICULAR_SERVICE = 1400;
+export const FUNICULAR_SERVICE_2 = 1401;
+export const ALL_FUNICULAR_SERVICES = 1402;
+export const LAST_FUNICULAR_SERVICE = ALL_FUNICULAR_SERVICES;
 
 // taxi services
-var TAXI_SERVICE = 1500;
-var COMMUNAL_TAXI_SERVICE = 1501;
-var WATER_TAXI_SERVICE = 1502;
-var RAIL_TAXI_SERVICE = 1503;
-var BIKE_TAXI_SERVICE = 1504;
-var LICENSED_TAXI_SERVICE = 1505;
-var PRIVATE_HIRE_SERVICE_VEHICLE = 1506;
-var ALL_TAXI_SERVICES = 1507;
-var LAST_TAXI_SERVICE = ALL_TAXI_SERVICES;
+export const TAXI_SERVICE = 1500;
+export const COMMUNAL_TAXI_SERVICE = 1501;
+export const WATER_TAXI_SERVICE = 1502;
+export const RAIL_TAXI_SERVICE = 1503;
+export const BIKE_TAXI_SERVICE = 1504;
+export const LICENSED_TAXI_SERVICE = 1505;
+export const PRIVATE_HIRE_SERVICE_VEHICLE = 1506;
+export const ALL_TAXI_SERVICES = 1507;
+export const LAST_TAXI_SERVICE = ALL_TAXI_SERVICES;
 
 // self drive
-var SELF_DRIVE = 1600;
-var HIRE_CAR = 1601;
-var HIRE_VAN = 1602;
-var HIRE_MOTORBIKE = 1603;
-var HIRE_CYCLE = 1604;
-var LAST_SELF_DRIVE = HIRE_CYCLE;
+export const SELF_DRIVE = 1600;
+export const HIRE_CAR = 1601;
+export const HIRE_VAN = 1602;
+export const HIRE_MOTORBIKE = 1603;
+export const HIRE_CYCLE = 1604;
+export const LAST_SELF_DRIVE = HIRE_CYCLE;
 
 // misc. service
-var MISCELLANEOUS_SERVICE = 1700;
-var CABLE_CAR = 1701;
-var HORSE_DRAWN_CARRIAGE = 1702;
-var LAST_MISCELLANEOUS_SERVCE = HORSE_DRAWN_CARRIAGE;
+export const MISCELLANEOUS_SERVICE = 1700;
+export const CABLE_CAR = 1701;
+export const HORSE_DRAWN_CARRIAGE = 1702;
+export const LAST_MISCELLANEOUS_SERVCE = HORSE_DRAWN_CARRIAGE;
 
 /**
  * returns the super type of a given HVT type code, or -1 if the supplied code
  * is not among the defined codes
  */
-function supertypeOf(type) {
+export function supertypeOf(type) {
     if (type >= RAILWAY_SERVICE && type <= LAST_RAIL_SERVICE)
         return RAILWAY_SERVICE;
     else if (type >= COACH_SERVICE && type <= LAST_COACH_SERVICE)
diff --git a/src/instructionRow.js b/src/instructionRow.js
index f8f4cdc9..571a19d0 100644
--- a/src/instructionRow.js
+++ b/src/instructionRow.js
@@ -20,28 +20,25 @@
  *         Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Utils = imports.utils;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import * as Utils from './utils.js';
 
-var InstructionRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/instruction-row.ui',
-    InternalChildren: [ 'directionImage',
-                        'instructionLabel',
-                        'distanceLabel' ]
-}, class InstructionRow extends Gtk.ListBoxRow {
+export class InstructionRow extends Gtk.ListBoxRow {
 
-    _init(params) {
-        this.turnPoint = params.turnPoint;
+    constructor(params) {
+        let turnPoint = params.turnPoint;
         delete params.turnPoint;
 
-        this._hasColor = params.hasColor;
+        let hasColor = params.hasColor;
         delete params.hasColor;
 
         let lines = params.lines;
         delete params.lines;
 
-        super._init(params);
+        super(params);
+
+        this.turnPoint = turnPoint;
 
         if (lines)
             this._instructionLabel.lines = lines;
@@ -54,7 +51,7 @@ var InstructionRow = GObject.registerClass({
          * the proper GtkIconLookupflags to re-color the icon as symbolic.
          * When we load the PixBuf from the SVG ourself, we get the color.
          */
-        if (this._hasColor) {
+        if (hasColor) {
             let theme = Gtk.IconTheme.get_default();
             let iconName = this.turnPoint.iconName;
             this._directionImage.pixbuf = theme.load_icon(iconName, 0, 0);
@@ -65,4 +62,11 @@ var InstructionRow = GObject.registerClass({
         if (this.turnPoint.distance > 0)
             this._distanceLabel.label = Utils.prettyDistance(this.turnPoint.distance);
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/instruction-row.ui',
+    InternalChildren: [ 'directionImage',
+                        'instructionLabel',
+                        'distanceLabel' ]
+}, InstructionRow);
diff --git a/src/kmlShapeLayer.js b/src/kmlShapeLayer.js
index c7ef0a1f..cee3997f 100644
--- a/src/kmlShapeLayer.js
+++ b/src/kmlShapeLayer.js
@@ -17,23 +17,28 @@
  * Author: Hashem Nasarat <hashem riseup net>
  */
 
-const GObject = imports.gi.GObject;
-
-const GeoJSONSource = imports.geoJSONSource;
-const ShapeLayer = imports.shapeLayer;
-const Utils = imports.utils;
-const Togeojson = imports.togeojson.togeojson;
-const Domparser = imports.xmldom.domparser;
-
-var KmlShapeLayer = GObject.registerClass(
-class KmlShapeLayer extends ShapeLayer.ShapeLayer {
-    _init(params) {
-        super._init(params);
-
-        this._mapSource = new GeoJSONSource.GeoJSONSource({
-            mapView: this._mapView,
-            markerLayer: this._markerLayer
-        });
+import GObject from 'gi://GObject';
+
+import {GeoJSONSource} from './geoJSONSource.js';
+import {ShapeLayer} from './shapeLayer.js';
+import * as Utils from './utils.js';
+import * as Togeojson from './togeojson/togeojson.js';
+import * as Domparser from './xmldom/domparser.js';
+
+export class KmlShapeLayer extends ShapeLayer {
+
+    static mimeTypes = ['application/vnd.google-earth.kml+xml'];
+    static displayName = 'KML';
+
+    static createInstance(params) {
+        return new KmlShapeLayer(params);
+    }
+
+    constructor(params) {
+        super(params);
+
+        this._mapSource = new GeoJSONSource({ mapView: this._mapView,
+                                              markerLayer: this._markerLayer });
     }
 
     _parseContent() {
@@ -42,10 +47,6 @@ class KmlShapeLayer extends ShapeLayer.ShapeLayer {
         let json = Togeojson.toGeoJSON.kml(parser.parseFromString(s));
         this._mapSource.parse(json);
     }
-});
+}
 
-KmlShapeLayer.mimeTypes = ['application/vnd.google-earth.kml+xml'];
-KmlShapeLayer.displayName = 'KML';
-KmlShapeLayer.createInstance = function(params) {
-    return new KmlShapeLayer(params);
-};
+GObject.registerClass(KmlShapeLayer);
diff --git a/src/layersPopover.js b/src/layersPopover.js
index d421b71f..ed6815c5 100644
--- a/src/layersPopover.js
+++ b/src/layersPopover.js
@@ -17,34 +17,31 @@
  * Author: Dario Di Nucci <linkin88mail gmail com>
  */
 
-const Champlain = imports.gi.Champlain;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Gdk = imports.gi.Gdk;
-const Hdy = imports.gi.Handy;
-
-const Application = imports.application;
-const MapSource = imports.mapSource;
-const MapView = imports.mapView;
-const Service = imports.service;
-const ShapeLayer = imports.shapeLayer;
-const Utils = imports.utils;
+import Champlain from 'gi://Champlain';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Gdk from 'gi://Gdk';
+import Handy from 'gi://Handy';
+
+import {Application} from './application.js';
+import * as MapSource from './mapSource.js';
+import {MapView} from './mapView.js';
+import * as Service from './service.js';
+import {ShapeLayer} from './shapeLayer.js';
+import * as Utils from './utils.js';
 
 const PREVIEW_WIDTH = 230;
 const PREVIEW_HEIGHT = 80;
 
-var ShapeLayerRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/shape-layer-row.ui',
-    Children: ['closeButton'],
-    InternalChildren: ['layerLabel', 'visibleButton']
-}, class ShapeLayerRow extends Gtk.ListBoxRow {
+export class ShapeLayerRow extends Gtk.ListBoxRow {
 
-    _init(params) {
-        this.shapeLayer = params.shapeLayer;
+    constructor(params) {
+        let shapeLayer = params.shapeLayer;
         delete params.shapeLayer;
 
-        super._init(params);
+        super(params);
 
+        this.shapeLayer = shapeLayer;
         this._layerLabel.label = this.shapeLayer.getName();
         this._layerLabel.tooltip_text = this.shapeLayer.file.get_parse_name();
         this._visibleButton.connect('clicked', () => {
@@ -58,27 +55,23 @@ var ShapeLayerRow = GObject.registerClass({
                 image.icon_name = 'layer-not-visible-symbolic';
         });
     }
-});
+}
 
-var LayersPopover = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/layers-popover.ui',
-    InternalChildren: [ 'streetLayerButton',
-                        'aerialLayerButton',
-                        'streetLayerImage',
-                        'aerialLayerImage',
-                        'hybridAerialRevealer',
-                        'layersListBox',
-                        'loadLayerButton' ]
-}, class LayersPopover extends Gtk.Popover {
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/shape-layer-row.ui',
+    Children: ['closeButton'],
+    InternalChildren: ['layerLabel', 'visibleButton']
+}, ShapeLayerRow);
 
-    _init(params) {
-        this._mapView = params.mapView;
-        delete params.mapView;
+export class LayersPopover extends Gtk.Popover {
 
-        super._init({ width_request: 200,
-                      no_show_all: true,
-                      transitions_enabled: false,
-                      visible: false });
+    constructor(params) {
+        super({ width_request: 200,
+                no_show_all: true,
+                transitions_enabled: false,
+                visible: false });
+
+        this._mapView = params.mapView;
 
         this._aerialLayerButton.join_group(this._streetLayerButton);
 
@@ -145,7 +138,7 @@ var LayersPopover = GObject.registerClass({
                                        this._setLayerPreviews.bind(this));
             this._mapView.view.connect("notify::longitude",
                                        this._setLayerPreviews.bind(this));
-            Hdy.StyleManager.get_default().connect("notify::dark",
+            Handy.StyleManager.get_default().connect("notify::dark",
                                                     this._onDarkChanged.bind(this));
             Application.settings.connect("changed::hybrid-aerial",
                                          this._onHybridAerialChanged.bind(this));
@@ -163,7 +156,7 @@ var LayersPopover = GObject.registerClass({
 
     _onDarkChanged() {
         if (Service.getService().tiles.streetDark &&
-            Hdy.StyleManager.get_default().dark) {
+            Handy.StyleManager.get_default().dark) {
             this._setLayerPreviewImage('streetDark', true);
         } else {
             this._setLayerPreviewImage('street', true);
@@ -181,7 +174,7 @@ var LayersPopover = GObject.registerClass({
 
     _setLayerPreviews() {
         if (Service.getService().tiles.streetDark &&
-            Hdy.StyleManager.get_default().dark) {
+            Handy.StyleManager.get_default().dark) {
             this._setLayerPreviewImage('streetDark');
         } else {
             this._setLayerPreviewImage('street');
@@ -264,4 +257,15 @@ var LayersPopover = GObject.registerClass({
         this._layersListBox.show();
         return row;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/layers-popover.ui',
+    InternalChildren: [ 'streetLayerButton',
+                        'aerialLayerButton',
+                        'streetLayerImage',
+                        'aerialLayerImage',
+                        'hybridAerialRevealer',
+                        'layersListBox',
+                        'loadLayerButton' ]
+}, LayersPopover);
diff --git a/src/location.js b/src/location.js
index 88427abc..1a0fe898 100644
--- a/src/location.js
+++ b/src/location.js
@@ -21,18 +21,18 @@
  *          Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Geocode = imports.gi.GeocodeGlib;
-const GObject = imports.gi.GObject;
+import Geocode from 'gi://GeocodeGlib';
+import GObject from 'gi://GObject';
 
 /* Adds heading to Geocode.Location */
-var Location = GObject.registerClass(
-class Location extends Geocode.Location {
+export class Location extends Geocode.Location {
 
-    _init(params) {
-        this._heading = params.heading;
+    constructor(params) {
+        let heading = params.heading;
         delete params.heading;
 
-        super._init(params);
+        super(params);
+        this._heading = heading;
     }
 
     get heading() {
@@ -42,4 +42,6 @@ class Location extends Geocode.Location {
     set heading(v) {
         this._heading = v;
     }
-});
+}
+
+GObject.registerClass(Location);
diff --git a/src/locationServiceDialog.js b/src/locationServiceDialog.js
index 4e459556..d215ab01 100644
--- a/src/locationServiceDialog.js
+++ b/src/locationServiceDialog.js
@@ -20,26 +20,22 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Gdk = imports.gi.Gdk;
-const Gio = imports.gi.Gio;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gdk from 'gi://Gdk';
+import Gio from 'gi://Gio';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Utils = imports.utils;
+import * as Utils from './utils.js';
 
 const _PRIVACY_PANEL = 'gnome-privacy-panel.desktop';
 
-var LocationServiceDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/location-service-dialog.ui',
-    InternalChildren: [ 'cancelButton',
-                        'settingsButton'],
-}, class LocationServiceDialog extends Gtk.Dialog {
+export class LocationServiceDialog extends Gtk.Dialog {
 
-    _init(params) {
+    constructor(params) {
         /* This is a construct-only property and cannot be set by GtkBuilder */
         params.use_header_bar = true;
 
-        super._init(params);
+        super(params);
 
         this._settingsButton.connect('clicked', () => this._onSettings());
         this._cancelButton.connect('clicked', () => this._onCancel());
@@ -62,4 +58,10 @@ var LocationServiceDialog = GObject.registerClass({
     _onCancel() {
         this.response(Gtk.ResponseType.CANCEL);
     }
-});
\ No newline at end of file
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/location-service-dialog.ui',
+    InternalChildren: [ 'cancelButton',
+                        'settingsButton'],
+}, LocationServiceDialog);
diff --git a/src/longPrintLayout.js b/src/longPrintLayout.js
index 3882f4e9..4833319d 100644
--- a/src/longPrintLayout.js
+++ b/src/longPrintLayout.js
@@ -17,10 +17,10 @@
  * Author: Amisha Singla <amishas157 gmail com>
  */
 
-const GObject = imports.gi.GObject;
+import GObject from 'gi://GObject';
 
-const PrintLayout = imports.printLayout;
-const Route = imports.route;
+import {PrintLayout} from './printLayout.js';
+import {TurnPoint} from './route.js';
 
 const _NUM_MINIMAPS = 5;
 
@@ -37,24 +37,25 @@ const _MiniMapView = {
     ZOOM_LEVEL: 18
 };
 
-var LongPrintLayout = GObject.registerClass(
-class LongPrintLayout extends PrintLayout.PrintLayout {
+export class LongPrintLayout extends PrintLayout {
 
-    _init(params) {
-        this._route = params.route;
+    constructor(params) {
+        let route = params.route;
         delete params.route;
 
         /* (Header + 3 maps) + instructions */
         let totalSurfaces = 4 + this._route.turnPoints.length;
 
         /* Plus via points */
-        this._route.turnPoints.forEach((turnPoint) => {
-            if (turnPoint.type === Route.TurnPointType.VIA)
+        route.turnPoints.forEach((turnPoint) => {
+            if (turnPoint.type === TurnPoint.Type.VIA)
                 totalSurfaces++;
         });
         params.totalSurfaces = totalSurfaces;
 
-        super._init(params);
+        super(params);
+
+        this._route = route;
     }
 
     render() {
@@ -137,4 +138,4 @@ class LongPrintLayout extends PrintLayout.PrintLayout {
         this._drawMapView(miniMapViewWidth, miniMapViewHeight,
                           miniMapViewZoomLevel, points);
     }
-});
+}
diff --git a/src/main.js b/src/main.js
index 6e4fa113..d46faa94 100644
--- a/src/main.js
+++ b/src/main.js
@@ -20,27 +20,29 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
+import 'gi://Champlain?version=0.12';
+import 'gi://Clutter?version=1.0';
+import 'gi://Cogl?version=1.0';
+import 'gi://GeocodeGlib?version=1.0';
+import 'gi://Gdk?version=3.0';
+import 'gi://GdkPixbuf?version=2.0';
+import 'gi://Gio?version=2.0';
+import 'gi://GLib?version=2.0';
+import 'gi://GObject?version=2.0';
+import 'gi://Gtk?version=3.0';
+import 'gi://GtkChamplain?version=0.12';
+import 'gi://GtkClutter?version=1.0';
+import 'gi://GWeather?version=4.0';
+import 'gi://Handy?version=1';
+import 'gi://Rest?version=0.7';
+import 'gi://Soup?version=2.4';
+
+import * as system from 'system';
+
+import {Application} from './application.js';
+
 pkg.initGettext();
 pkg.initFormat();
-pkg.require({ 'cairo': '1.0',
-              'Champlain': '0.12',
-              'Clutter': '1.0',
-              'Cogl': '1.0',
-              'GeocodeGlib': '1.0',
-              'Gdk': '3.0',
-              'GdkPixbuf': '2.0',
-              'Gio': '2.0',
-              'GLib': '2.0',
-              'GObject': '2.0',
-              'Gtk': '3.0',
-              'GtkChamplain': '0.12',
-              'GtkClutter': '1.0',
-              'GWeather': '4.0',
-              'Handy': '1',
-              'Rest': '0.7',
-              'Soup': '2.4' });
-
-const Application = imports.application;
 
 function main(args) {
     /* Add prototype to get last element of an array.
@@ -53,6 +55,8 @@ function main(args) {
         }
     }
 
-    let application = new Application.Application();
+    let application = new Application();
     return application.run(args);
 }
+
+main([system.programInvocationName, ...system.programArgs]);
diff --git a/src/mainWindow.js b/src/mainWindow.js
index bb4fc69e..d28843be 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -20,44 +20,44 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const _ = imports.gettext.gettext;
-
-const Champlain = imports.gi.Champlain;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gdk = imports.gi.Gdk;
-const Gio = imports.gi.Gio;
-const Gtk = imports.gi.Gtk;
+import gettext from 'gettext';
+
+import Champlain from 'gi://Champlain';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gdk from 'gi://Gdk';
+import Gio from 'gi://Gio';
+import Gtk from 'gi://Gtk';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const ContextMenu = imports.contextMenu;
-const ExportViewDialog = imports.exportViewDialog;
-const FavoritesPopover = imports.favoritesPopover;
-const Geoclue = imports.geoclue;
-const GeocodeFactory = imports.geocode;
-const HeaderBar = imports.headerBar;
-const LocationServiceDialog = imports.locationServiceDialog;
-const MapView = imports.mapView;
-const PlaceBar = imports.placeBar;
-const PlaceEntry = imports.placeEntry;
-const PlaceStore = imports.placeStore;
-const PrintOperation = imports.printOperation;
-const Service = imports.service;
-const ShapeLayer = imports.shapeLayer;
-const Sidebar = imports.sidebar;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import {ContextMenu} from './contextMenu.js';
+import {ExportViewDialog} from './exportViewDialog.js';
+import {FavoritesPopover} from './favoritesPopover.js';
+import * as Geoclue from './geoclue.js';
+import * as GeocodeFactory from './geocode.js';
+import {HeaderBarLeft, HeaderBarRight} from './headerBar.js';
+import {LocationServiceDialog} from './locationServiceDialog.js';
+import {MapView} from './mapView.js';
+import {PlaceBar} from './placeBar.js';
+import {PlaceEntry} from './placeEntry.js';
+import {PlaceStore} from './placeStore.js';
+import {PrintOperation} from './printOperation.js';
+import * as Service from './service.js';
+import {ShapeLayer} from './shapeLayer.js';
+import {Sidebar} from './sidebar.js';
+import * as Utils from './utils.js';
+
+const _ = gettext.gettext;
 
 const _CONFIGURE_ID_TIMEOUT = 100; // msecs
 const _ADAPTIVE_VIEW_WIDTH = 700;
 const _PLACE_ENTRY_MARGIN = 35;
 
-var ShapeLayerFileChooser = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/shape-layer-file-chooser.ui'
-}, class ShapeLayerFileChooser extends Gtk.FileChooserNative {
+class ShapeLayerFileChooser extends Gtk.FileChooserNative {
 
-    _init(params) {
-        super._init(params);
+    constructor(params) {
+        super(params);
         let allFilter = new Gtk.FileFilter();
         allFilter.set_name(_("All Layer Files"));
         this.add_filter(allFilter);
@@ -75,16 +75,13 @@ var ShapeLayerFileChooser = GObject.registerClass({
             this.add_filter(filter);
         });
     }
-});
+}
 
-var MainWindow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/main-window.ui',
-    InternalChildren: [ 'headerBar',
-                        'grid',
-                        'actionBar',
-                        'actionBarRevealer',
-                        'placeBarContainer']
-}, class MainWindow extends Gtk.ApplicationWindow {
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/shape-layer-file-chooser.ui'
+}, ShapeLayerFileChooser);
+
+export class MainWindow extends Gtk.ApplicationWindow {
 
     get mapView() {
         return this._mapView;
@@ -94,12 +91,12 @@ var MainWindow = GObject.registerClass({
         return this._placeEntry;
     }
 
-    _init(params) {
-        super._init(params);
+    constructor(params) {
+        super(params);
 
         this._configureId = 0;
 
-        this._mapView = new MapView.MapView({
+        this._mapView = new MapView({
             mapType: this.application.local_tile_path ?
                 MapView.MapType.LOCAL : undefined,
             mainWindow: this });
@@ -110,8 +107,8 @@ var MainWindow = GObject.registerClass({
 
         this._sidebar = this._createSidebar();
 
-        this._contextMenu = new ContextMenu.ContextMenu({ mapView: this._mapView,
-                                                          mainWindow: this });
+        this._contextMenu = new ContextMenu({ mapView: this._mapView,
+                                              mainWindow: this });
 
         if (pkg.name.endsWith('.Devel'))
             this.get_style_context().add_class('devel');
@@ -137,14 +134,13 @@ var MainWindow = GObject.registerClass({
     }
 
     _createPlaceEntry() {
-        let placeEntry = new PlaceEntry.PlaceEntry({ mapView: this._mapView,
-                                                     visible: true,
-                                                     margin_start: _PLACE_ENTRY_MARGIN,
-                                                     margin_end: _PLACE_ENTRY_MARGIN,
-                                                     max_width_chars: 50,
-                                                     loupe: true,
-                                                     matchRoute: true
-                                                   });
+        let placeEntry = new PlaceEntry({ mapView: this._mapView,
+                                          visible: true,
+                                          margin_start: _PLACE_ENTRY_MARGIN,
+                                          margin_end: _PLACE_ENTRY_MARGIN,
+                                          max_width_chars: 50,
+                                          loupe: true,
+                                          matchRoute: true });
         placeEntry.connect('notify::place', () => {
             if (placeEntry.place) {
                 this._mapView.showPlace(placeEntry.place, true);
@@ -158,7 +154,7 @@ var MainWindow = GObject.registerClass({
     }
 
     _createSidebar() {
-        let sidebar = new Sidebar.Sidebar(this._mapView);
+        let sidebar = new Sidebar(this._mapView);
 
         Application.routeQuery.connect('notify', () => this._setRevealSidebar(true));
 
@@ -166,8 +162,7 @@ var MainWindow = GObject.registerClass({
     }
 
     _initPlaceBar() {
-        this._placeBar = new PlaceBar.PlaceBar({ mapView: this._mapView,
-                                                 visible: true });
+        this._placeBar = new PlaceBar({ mapView: this._mapView, visible: true });
         this._placeBarContainer.add(this._placeBar);
 
         this.application.bind_property('selected-place',
@@ -348,16 +343,10 @@ var MainWindow = GObject.registerClass({
     }
 
     _initHeaderbar() {
-        this._headerBarLeft = new HeaderBar.HeaderBarLeft({
-            mapView: this._mapView,
-            application: this.application
-        });
+        this._headerBarLeft = new HeaderBarLeft({ mapView: this._mapView });
         this._headerBar.pack_start(this._headerBarLeft);
 
-        this._headerBarRight = new HeaderBar.HeaderBarRight({
-            mapView: this._mapView,
-            application: this.application
-        });
+        this._headerBarRight = new HeaderBarRight({ mapView: this._mapView });
         this._headerBar.pack_end(this._headerBarRight);
 
         this._placeEntry = this._createPlaceEntry();
@@ -367,16 +356,10 @@ var MainWindow = GObject.registerClass({
                                     this._updateLocationSensitivity.bind(this));
 
         // action bar, for when the window is too narrow for the full headerbar
-        this._actionBarLeft =  new HeaderBar.HeaderBarLeft({
-            mapView: this._mapView,
-            application: this.application
-        })
+        this._actionBarLeft =  new HeaderBarLeft({ mapView: this._mapView });
         this._actionBar.pack_start(this._actionBarLeft);
 
-        this._actionBarRight = new HeaderBar.HeaderBarRight({
-            mapView: this._mapView,
-            application: this.application
-        })
+        this._actionBarRight = new HeaderBarRight({ mapView: this._mapView });
         this._actionBar.pack_end(this._actionBarRight);
 
         this.connect('size-allocate', () => {
@@ -507,7 +490,7 @@ var MainWindow = GObject.registerClass({
         let bbox = view.get_bounding_box();
         let [latitude, longitude] = bbox.get_center();
 
-        let dialog = new ExportViewDialog.ExportViewDialog({
+        let dialog = new ExportViewDialog({
             transient_for: this,
             modal: true,
             surface: surface,
@@ -675,4 +658,13 @@ var MainWindow = GObject.registerClass({
         });
         this._fileChooser.show();
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/main-window.ui',
+    InternalChildren: [ 'headerBar',
+                        'grid',
+                        'actionBar',
+                        'actionBarRevealer',
+                        'placeBarContainer']
+}, MainWindow);
diff --git a/src/mapBubble.js b/src/mapBubble.js
index 1d92c9ee..508c82c8 100644
--- a/src/mapBubble.js
+++ b/src/mapBubble.js
@@ -19,21 +19,21 @@
  * Author: Damián Nohales <damiannohales gmail com>
  */
 
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const ContactPlace = imports.contactPlace;
-const GeocodeFactory = imports.geocode;
-const Place = imports.place;
-const PlaceView = imports.placeView;
-const PlaceButtons = imports.placeButtons;
-const PlaceFormatter = imports.placeFormatter;
-const PlaceStore = imports.placeStore;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import {ContactPlace} from './contactPlace.js';
+import * as GeocodeFactory from './geocode.js';
+import {Place} from './place.js';
+import {PlaceView} from './placeView.js';
+import {PlaceButtons} from './placeButtons.js';
+import {PlaceFormatter} from './placeFormatter.js';
+import {PlaceStore} from './placeStore.js';
+import * as Utils from './utils.js';
 
 /* Maximum width of the popover content before it's forced to wrap */
 const MAX_CONTENT_WIDTH = 350;
@@ -41,10 +41,9 @@ const MAX_CONTENT_WIDTH = 350;
    contents */
 const HEIGHT_MARGIN = 100;
 
-var MapBubble = GObject.registerClass(
-class MapBubble extends Gtk.Popover {
+export class MapBubble extends Gtk.Popover {
 
-    _init(params) {
+    constructor(params) {
         let place = params.place;
         delete params.place;
 
@@ -55,9 +54,9 @@ class MapBubble extends Gtk.Popover {
         params.transitions_enabled = false;
         params.modal = false;
 
-        super._init(params);
+        super(params);
 
-        let content = new PlaceView.PlaceView({ place, mapView, visible: true });
+        let content = new PlaceView({ place, mapView, visible: true });
 
         let scrolledWindow = new MapBubbleScrolledWindow({ visible: true,
                                                            propagateNaturalWidth: true,
@@ -68,10 +67,11 @@ class MapBubble extends Gtk.Popover {
 
         this.get_style_context().add_class("map-bubble");
     }
-});
+}
 
-var MapBubbleScrolledWindow = GObject.registerClass(
-class MapBubbleScrolledWindow extends Gtk.ScrolledWindow {
+GObject.registerClass(MapBubble);
+
+export class MapBubbleScrolledWindow extends Gtk.ScrolledWindow {
     vfunc_get_preferred_width() {
         let [min, nat] = this.get_child().get_preferred_width();
         min = Math.min(min, MAX_CONTENT_WIDTH);
@@ -109,5 +109,7 @@ class MapBubbleScrolledWindow extends Gtk.ScrolledWindow {
 
         return super.vfunc_draw(cr);
     }
-});
+}
+
+GObject.registerClass(MapBubbleScrolledWindow);
 
diff --git a/src/mapMarker.js b/src/mapMarker.js
index b5a0e7fa..7e09befd 100644
--- a/src/mapMarker.js
+++ b/src/mapMarker.js
@@ -19,55 +19,36 @@
  * Author: Damián Nohales <damiannohales gmail com>
  */
 
-const Cairo = imports.cairo;
-const Champlain = imports.gi.Champlain;
-const Clutter = imports.gi.Clutter;
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Cairo from 'cairo';
+import Champlain from 'gi://Champlain';
+import Clutter from 'gi://Clutter';
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const MapBubble = imports.mapBubble;
-const MapWalker = imports.mapWalker;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import {MapBubble} from './mapBubble.js';
+import {MapWalker} from './mapWalker.js';
+import * as Utils from './utils.js';
 
-var MapMarker = GObject.registerClass({
-    Implements: [Champlain.Exportable],
-    Abstract: true,
-    Signals: {
-        'gone-to': { }
-    },
-    Properties: {
-        'surface': GObject.ParamSpec.override('surface',
-                                              Champlain.Exportable),
-        'view-latitude': GObject.ParamSpec.double('view-latitude', '', '',
-                                                  GObject.ParamFlags.READABLE |
-                                                  GObject.ParamFlags.WRITABLE,
-                                                  -90, 90, 0),
-        'view-longitude': GObject.ParamSpec.double('view-longitude', '', '',
-                                                   GObject.ParamFlags.READABLE |
-                                                   GObject.ParamFlags.WRITABLE,
-                                                   -180, 180, 0),
-        'view-zoom-level': GObject.ParamSpec.int('view-zoom-level', '', '',
-                                                 GObject.ParamFlags.READABLE |
-                                                 GObject.ParamFlags.WRITABLE,
-                                                 0, 20, 3)
-    }
-}, class MapMarker extends Champlain.Marker {
+export class MapMarker extends Champlain.Marker {
 
-    _init(params) {
-        this._place = params.place;
+    constructor(params) {
+        let place = params.place;
         delete params.place;
 
-        this._mapView = params.mapView;
+        let mapView = params.mapView;
         delete params.mapView;
 
-        params.latitude = this.place.location.latitude;
-        params.longitude = this.place.location.longitude;
+        params.latitude = place.location.latitude;
+        params.longitude = place.location.longitude;
         params.selectable = true;
 
-        super._init(params);
+        super(params);
+
+        this._place = place;
+        this._mapView = mapView;
 
         this.connect('notify::size', this._translateMarkerPosition.bind(this));
         if (this._mapView) {
@@ -208,8 +189,8 @@ var MapMarker = GObject.registerClass({
     get bubble() {
         if (this._bubble === undefined && this._hasBubble()) {
             if (this._place.name) {
-                this._bubble = new MapBubble.MapBubble({ place: this._place,
-                                                         mapView: this._mapView });
+                this._bubble = new MapBubble({ place: this._place,
+                                               mapView: this._mapView });
             }
         }
 
@@ -371,7 +352,7 @@ var MapMarker = GObject.registerClass({
 
     get walker() {
         if (this._walker === undefined)
-            this._walker = new MapWalker.MapWalker(this.place, this._mapView);
+            this._walker = new MapWalker(this.place, this._mapView);
 
         return this._walker;
     }
@@ -412,4 +393,28 @@ var MapMarker = GObject.registerClass({
             }
         }
     }
-});
+}
+
+GObject.registerClass({
+    Implements: [Champlain.Exportable],
+    Abstract: true,
+    Signals: {
+        'gone-to': { }
+    },
+    Properties: {
+        'surface': GObject.ParamSpec.override('surface',
+                                              Champlain.Exportable),
+        'view-latitude': GObject.ParamSpec.double('view-latitude', '', '',
+                                                  GObject.ParamFlags.READABLE |
+                                                  GObject.ParamFlags.WRITABLE,
+                                                  -90, 90, 0),
+        'view-longitude': GObject.ParamSpec.double('view-longitude', '', '',
+                                                   GObject.ParamFlags.READABLE |
+                                                   GObject.ParamFlags.WRITABLE,
+                                                   -180, 180, 0),
+        'view-zoom-level': GObject.ParamSpec.int('view-zoom-level', '', '',
+                                                 GObject.ParamFlags.READABLE |
+                                                 GObject.ParamFlags.WRITABLE,
+                                                 0, 20, 3)
+    }
+}, MapMarker);
diff --git a/src/mapSource.js b/src/mapSource.js
index dd25a6ce..98373ab5 100644
--- a/src/mapSource.js
+++ b/src/mapSource.js
@@ -17,10 +17,10 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Champlain = imports.gi.Champlain;
+import Champlain from 'gi://Champlain';
 
-const Service = imports.service;
-const Utils = imports.utils;
+import * as Service from './service.js';
+import * as Utils from './utils.js';
 
 const _FILE_CACHE_SIZE_LIMIT = (10 * 1024 * 1024); /* 10Mb */
 const _MEMORY_CACHE_SIZE_LIMIT = 100; /* number of tiles */
@@ -72,22 +72,22 @@ function _createCachedSource(source) {
     return sourceChain;
 }
 
-function createAerialSource() {
+export function createAerialSource() {
     return _createCachedSource(Service.getService().tiles.aerial);
 }
 
-function createHybridAerialSource() {
+export function createHybridAerialSource() {
     return _createCachedSource(Service.getService().tiles.hybridAerial);
 }
 
-function createStreetSource() {
+export function createStreetSource() {
     return _createCachedSource(Service.getService().tiles.street);
 }
 
-function createStreetDarkSource() {
+export function createStreetDarkSource() {
     return _createCachedSource(Service.getService().tiles.streetDark)
 }
 
-function createPrintSource() {
+export function createPrintSource() {
     return _createCachedSource(Service.getService().tiles.print);
 }
diff --git a/src/mapView.js b/src/mapView.js
index 103a40d3..1f868d72 100644
--- a/src/mapView.js
+++ b/src/mapView.js
@@ -19,58 +19,44 @@
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const Champlain = imports.gi.Champlain;
-const Clutter = imports.gi.Clutter;
-const GObject = imports.gi.GObject;
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const Gtk = imports.gi.Gtk;
-const GtkChamplain = imports.gi.GtkChamplain;
-const Hdy = imports.gi.Handy;
+import Champlain from 'gi://Champlain';
+import Clutter from 'gi://Clutter';
+import GObject from 'gi://GObject';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import Gtk from 'gi://Gtk';
+import GtkChamplain from 'gi://GtkChamplain';
+import Handy from 'gi://Handy';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const BoundingBox = imports.boundingBox;
-const ContactPlace = imports.contactPlace;
-const Color = imports.color;
-const Geoclue = imports.geoclue;
-const GeoJSONShapeLayer = imports.geoJSONShapeLayer;
-const KmlShapeLayer = imports.kmlShapeLayer;
-const GpxShapeLayer = imports.gpxShapeLayer;
-const Location = imports.location;
-const Maps = imports.gi.GnomeMaps;
-const MapSource = imports.mapSource;
-const MapWalker = imports.mapWalker;
-const Place = imports.place;
-const PlaceMarker = imports.placeMarker;
-const RouteQuery = imports.routeQuery;
-const Service = imports.service;
-const ShapeLayer = imports.shapeLayer;
-const StoredRoute = imports.storedRoute;
-const TransitArrivalMarker = imports.transitArrivalMarker;
-const TransitBoardMarker = imports.transitBoardMarker;
-const TransitWalkMarker = imports.transitWalkMarker;
-const TurnPointMarker = imports.turnPointMarker;
-const UserLocationMarker = imports.userLocationMarker;
-const Utils = imports.utils;
-
-var MapType = {
-    LOCAL: 'MapsLocalSource',
-    STREET: 'MapsStreetSource',
-    AERIAL: 'MapsAerialSource'
-};
+import GnomeMaps from 'gi://GnomeMaps';
+
+import {Application} from './application.js';
+import {BoundingBox} from './boundingBox.js';
+import {ContactPlace} from './contactPlace.js';
+import * as Color from './color.js';
+import * as Geoclue from './geoclue.js';
+import {GeoJSONShapeLayer} from './geoJSONShapeLayer.js';
+import {KmlShapeLayer} from './kmlShapeLayer.js';
+import {GpxShapeLayer} from './gpxShapeLayer.js';
+import {Location} from './location.js';
+import * as MapSource from './mapSource.js';
+import {MapWalker} from './mapWalker.js';
+import {Place} from './place.js';
+import {PlaceMarker} from './placeMarker.js';
+import * as Service from './service.js';
+import {ShapeLayer} from './shapeLayer.js';
+import {StoredRoute} from './storedRoute.js';
+import {TransitArrivalMarker} from './transitArrivalMarker.js';
+import {TransitBoardMarker} from './transitBoardMarker.js';
+import {TransitWalkMarker} from './transitWalkMarker.js';
+import {TurnPointMarker} from './turnPointMarker.js';
+import {UserLocationMarker} from './userLocationMarker.js';
+import * as Utils from './utils.js';
+
 const _LOCATION_STORE_TIMEOUT = 500;
 const MapMinZoom = 2;
 
-/*
- * Due to the mathematics of spherical mericator projection,
- * the map must be truncated at a latitude less than 90 degrees.
- */
-var MAX_LATITUDE = 85.05112;
-var MIN_LATITUDE = -85.05112;
-var MAX_LONGITUDE = 180;
-var MIN_LONGITUDE = -180;
-
 /* threashhold for route color luminance when we consider it more or less
  * as white, and draw an outline on the path */
 const OUTLINE_LUMINANCE_THREASHHOLD = 0.9;
@@ -92,33 +78,22 @@ const DASHED_ROUTE_LINE_GAP_LENGTH = 5;
 // Maximum limit of file size (20 MB) that can be loaded without user confirmation
 const FILE_SIZE_LIMIT_MB = 20;
 
-var MapView = GObject.registerClass({
-    Properties: {
-        // this property is true when the routing sidebar is active
-        'routingOpen': GObject.ParamSpec.boolean('routingOpen',
-                                                  'Routing open',
-                                                  'Routing sidebar open',
-                                                  GObject.ParamFlags.READABLE |
-                                                  GObject.ParamFlags.WRITABLE,
-                                                  false),
-        /* this property is true when a route is being shown on the map */
-        'routeShowing': GObject.ParamSpec.boolean('routeShowing',
-                                                 'Route showing',
-                                                 'Showing a route on the map',
-                                                 GObject.ParamFlags.READABLE |
-                                                 GObject.ParamFlags.WRITABLE,
-                                                 false)
-    },
-    Signals: {
-        'user-location-changed': {},
-        'going-to': {},
-        'going-to-user-location': {},
-        'gone-to-user-location': {},
-        'view-moved': {},
-        'marker-selected': { param_types: [Champlain.Marker] },
-        'map-type-changed': { param_types: [GObject.TYPE_STRING] }
-    },
-}, class MapView extends GtkChamplain.Embed {
+export class MapView extends GtkChamplain.Embed {
+
+    static MapType = {
+        LOCAL: 'MapsLocalSource',
+        STREET: 'MapsStreetSource',
+        AERIAL: 'MapsAerialSource'
+    }
+
+    /*
+     * Due to the mathematics of spherical mericator projection,
+     * the map must be truncated at a latitude less than 90 degrees.
+     */
+    static MAX_LATITUDE = 85.05112;
+    static MIN_LATITUDE = -85.05112;
+    static MAX_LONGITUDE = 180;
+    static MIN_LONGITUDE = -180;
 
     get routingOpen() {
         return this._routingOpen || this._instructionMarkerLayer.visible;
@@ -144,8 +119,8 @@ var MapView = GObject.registerClass({
         this.notify('routeShowing');
     }
 
-    _init(params) {
-        super._init();
+    constructor(params) {
+        super();
 
         let mapType = params.mapType || this._getStoredMapType();
         delete params.mapType;
@@ -208,7 +183,7 @@ var MapView = GObject.registerClass({
 
         // if dark tiles is available, setup handler to switch style
         if (Service.getService().tiles.streetDark) {
-            Hdy.StyleManager.get_default().connect('notify::dark',
+            Handy.StyleManager.get_default().connect('notify::dark',
                                                     this._onDarkChanged.bind(this));
         }
 
@@ -229,7 +204,7 @@ var MapView = GObject.registerClass({
         if (this._mapType === MapType.STREET) {
             let overlay_sources = this.view.get_overlay_sources();
 
-            if (Hdy.StyleManager.get_default().dark)
+            if (Handy.StyleManager.get_default().dark)
                 this.view.map_source = MapSource.createStreetDarkSource();
             else
                 this.view.map_source = MapSource.createStreetSource();
@@ -296,9 +271,9 @@ var MapView = GObject.registerClass({
         this._annotationMarkerLayer = new Champlain.MarkerLayer({ selection_mode: mode });
         this.view.add_layer(this._annotationMarkerLayer);
 
-        ShapeLayer.SUPPORTED_TYPES.push(GeoJSONShapeLayer.GeoJSONShapeLayer);
-        ShapeLayer.SUPPORTED_TYPES.push(KmlShapeLayer.KmlShapeLayer);
-        ShapeLayer.SUPPORTED_TYPES.push(GpxShapeLayer.GpxShapeLayer);
+        ShapeLayer.SUPPORTED_TYPES.push(GeoJSONShapeLayer);
+        ShapeLayer.SUPPORTED_TYPES.push(KmlShapeLayer);
+        ShapeLayer.SUPPORTED_TYPES.push(GpxShapeLayer);
 
         this._routeLayers = [];
     }
@@ -348,8 +323,8 @@ var MapView = GObject.registerClass({
         let mapType = Application.settings.get('map-type');
 
         // make sure it's a valid map type
-        for (let type in MapType) {
-            if (mapType === MapType[type]) {
+        for (let type in MapView.MapType) {
+            if (mapType === MapView.MapType[type]) {
                 return mapType;
             }
         }
@@ -369,10 +344,10 @@ var MapView = GObject.registerClass({
 
         this._mapType = mapType;
 
-        if (mapType !== MapType.LOCAL) {
+        if (mapType !== MapView.MapType.LOCAL) {
             let tiles = Service.getService().tiles;
 
-            if (mapType === MapType.AERIAL && tiles.aerial) {
+            if (mapType === MapView.MapType.AERIAL && tiles.aerial) {
                 if (tiles.hybridAerial &&
                     Application.settings.get('hybrid-aerial')) {
                     this.view.map_source = MapSource.createHybridAerialSource();
@@ -381,7 +356,7 @@ var MapView = GObject.registerClass({
                 }
             } else {
                 if (tiles.streetDark &&
-                    Hdy.StyleManager.get_default().dark) {
+                    Handy.StyleManager.get_default().dark) {
                     this.view.map_source = MapSource.createStreetDarkSource();
                 } else {
                     this.view.map_source = MapSource.createStreetSource();
@@ -391,7 +366,7 @@ var MapView = GObject.registerClass({
             Application.settings.set('map-type', mapType);
         } else {
             let renderer = new Champlain.ImageRenderer();
-            let source = new Maps.FileTileSource({
+            let source = new GnomeMaps.FileTileSource({
                 path: Utils.getBufferText(Application.application.local_tile_path),
                 renderer: renderer,
                 tile_size: Application.application.local_tile_size || 512
@@ -404,7 +379,7 @@ var MapView = GObject.registerClass({
                 let [lat, lon] = this.view.world.get_center();
                 this.view.center_on(lat, lon);
             } catch(e) {
-                this.setMapType(MapType.STREET);
+                this.setMapType(MapView.MapType.STREET);
                 Application.application.local_tile_path = false;
                 Utils.showDialog(e.message, Gtk.MessageType.ERROR, this._mainWindow);
             }
@@ -478,7 +453,7 @@ var MapView = GObject.registerClass({
     }
 
     _loadShapeLayers(files) {
-        let bbox = new BoundingBox.BoundingBox();
+        let bbox = new BoundingBox();
         this._remainingFilesToLoad = files.length;
 
         files.forEach((file) => {
@@ -515,14 +490,14 @@ var MapView = GObject.registerClass({
 
     goToGeoURI(uri) {
         try {
-            let location = new Location.Location({ heading: -1 });
+            let location = new Location({ heading: -1 });
             location.set_from_uri(uri);
 
-            let place = new Place.Place({ location: location,
-                                          name: location.description,
-                                          store: false });
-            let marker = new PlaceMarker.PlaceMarker({ place: place,
-                                                       mapView: this });
+            let place = new Place({ location: location,
+                                    name: location.description,
+                                    store: false });
+            let marker = new PlaceMarker({ place: place,
+                                           mapView: this });
             this._placeLayer.add_marker(marker);
             marker.goToAndSelect(true);
         } catch(e) {
@@ -535,8 +510,8 @@ var MapView = GObject.registerClass({
     goToHttpURL(url) {
         Place.parseHttpURL(url, (place, error) => {
             if (place) {
-                let marker = new PlaceMarker.PlaceMarker({ place: place,
-                                                           mapView: this });
+                let marker = new PlaceMarker({ place: place,
+                                               mapView: this });
 
                 this._placeLayer.add_marker(marker);
                 marker.goToAndSelect(true);
@@ -561,11 +536,11 @@ var MapView = GObject.registerClass({
         let lon = this.view.longitude > 0 ?
                   this.view.longitude - 180 : this.view.longitude + 180;
         let place =
-            new Place.Place({ location: new Location.Location({ latitude: lat,
-                                                                longitude: lon }),
-                              initialZoom: this.view.zoom_level });
+            new Place({ location: new Location({ latitude: lat,
+                                                 longitude: lon }),
+                        initialZoom: this.view.zoom_level });
 
-        new MapWalker.MapWalker(place, this).goTo(true);
+        new MapWalker(place, this).goTo(true);
     }
 
     userLocationVisible() {
@@ -586,8 +561,8 @@ var MapView = GObject.registerClass({
 
         if (!this._userLocation) {
             let place = Application.geoclue.place;
-            this._userLocation = new UserLocationMarker.UserLocationMarker({ place: place,
-                                                                             mapView: this });
+            this._userLocation = new UserLocationMarker({ place: place,
+                                                          mapView: this });
             this._userLocationLayer.remove_all();
             this._userLocation.addToLayer(this._userLocationLayer);
         }
@@ -626,17 +601,17 @@ var MapView = GObject.registerClass({
             else
                 Utils.debug('Invalid initial zoom level: ' + zoom);
 
-            if (lat >= MIN_LATITUDE && lat <= MAX_LATITUDE &&
-                lon >= MIN_LONGITUDE && lon <= MAX_LONGITUDE)
+            if (lat >= MapView.MIN_LATITUDE && lat <= MapView.MAX_LATITUDE &&
+                lon >= MapView.MIN_LONGITUDE && lon <= MapView.MAX_LONGITUDE)
                 this.view.center_on(location[0], location[1]);
             else
                 Utils.debug('Invalid initial coordinates: ' + lat + ', ' + lon);
         } else {
             /* bounding box. for backwards compatibility, not used anymore */
-            let bbox = new BoundingBox.BoundingBox({ top: location[0],
-                                                     bottom: location[1],
-                                                     left: location[2],
-                                                     right: location[3] });
+            let bbox = new BoundingBox({ top: location[0],
+                                         bottom: location[1],
+                                         left: location[2],
+                                         right: location[3] });
             this.view.connect("notify::realized", () => {
                 if (this.view.realized)
                     this.gotoBBox(bbox, true);
@@ -651,15 +626,15 @@ var MapView = GObject.registerClass({
         }
 
         let [lon, lat] = bbox.getCenter();
-        let place = new Place.Place({
-            location: new Location.Location({ latitude  : lat,
+        let place = new Place({
+            location: new Location({ latitude  : lat,
                                               longitude : lon }),
-            bounding_box: new Geocode.BoundingBox({ top    : bbox.top,
-                                                    bottom : bbox.bottom,
-                                                    left   : bbox.left,
-                                                    right  : bbox.right })
+            bounding_box: new GeocodeGlib.BoundingBox({ top    : bbox.top,
+                                                        bottom : bbox.bottom,
+                                                        left   : bbox.left,
+                                                        right  : bbox.right })
         });
-        new MapWalker.MapWalker(place, this).goTo(true, linear);
+        new MapWalker(place, this).goTo(true, linear);
     }
 
     getZoomLevelFittingBBox(bbox) {
@@ -697,8 +672,8 @@ var MapView = GObject.registerClass({
         if (turnPoint.isStop())
             return;
 
-        this._turnPointMarker = new TurnPointMarker.TurnPointMarker({ turnPoint: turnPoint,
-                                                                      mapView: this });
+        this._turnPointMarker = new TurnPointMarker({ turnPoint: turnPoint,
+                                                      mapView: this });
         this._instructionMarkerLayer.add_marker(this._turnPointMarker);
         this._turnPointMarker.goTo();
     }
@@ -707,9 +682,9 @@ var MapView = GObject.registerClass({
         if (this._turnPointMarker)
             this._turnPointMarker.destroy();
 
-        this._turnPointMarker = new TurnPointMarker.TurnPointMarker({ transitStop: transitStop,
-                                                                      transitLeg: transitLeg,
-                                                                      mapView: this });
+        this._turnPointMarker = new TurnPointMarker({ transitStop: transitStop,
+                                                      transitLeg: transitLeg,
+                                                      mapView: this });
         this._instructionMarkerLayer.add_marker(this._turnPointMarker);
         this._turnPointMarker.goTo();
     }
@@ -721,14 +696,14 @@ var MapView = GObject.registerClass({
 
         this._placeLayer.remove_all();
         places.forEach((p) => {
-            let place = new ContactPlace.ContactPlace({ place: p,
-                                                        contact: contact });
-            let marker = new PlaceMarker.PlaceMarker({ place: place,
-                                                       mapView: this });
+            let place = new ContactPlace({ place: p,
+                                           contact: contact });
+            let marker = new PlaceMarker({ place: place,
+                                           mapView: this });
             this._placeLayer.add_marker(marker);
         });
 
-        new MapWalker.MapWalker(places[0], this).goTo(true);
+        new MapWalker(places[0], this).goTo(true);
     }
 
     _showStoredRoute(stored) {
@@ -759,14 +734,14 @@ var MapView = GObject.registerClass({
     showPlace(place, animation) {
         this._placeLayer.remove_all();
 
-        if (place instanceof StoredRoute.StoredRoute) {
+        if (place instanceof StoredRoute) {
             this._showStoredRoute(place);
             return;
         }
 
         this.routingOpen = false;
-        let placeMarker = new PlaceMarker.PlaceMarker({ place: place,
-                                                        mapView: this });
+        let placeMarker = new PlaceMarker({ place: place,
+                                            mapView: this });
 
         this._placeLayer.add_marker(placeMarker);
         placeMarker.goToAndSelect(animation);
@@ -799,9 +774,9 @@ var MapView = GObject.registerClass({
         route.turnPoints.forEach((turnPoint) => {
             if (turnPoint.isStop()) {
                 let queryPoint = query.filledPoints[pointIndex];
-                let destinationMarker = new TurnPointMarker.TurnPointMarker({ turnPoint: turnPoint,
-                                                                              queryPoint: queryPoint,
-                                                                              mapView: this });
+                let destinationMarker = new TurnPointMarker({ turnPoint: turnPoint,
+                                                              queryPoint: queryPoint,
+                                                              mapView: this });
                 this._instructionMarkerLayer.add_marker(destinationMarker);
                 pointIndex++;
             }
@@ -869,12 +844,12 @@ var MapView = GObject.registerClass({
             /* add start marker */
             let start;
             if (!leg.transit) {
-                start = new TransitWalkMarker.TransitWalkMarker({ leg: leg,
-                                                                  previousLeg: previousLeg,
-                                                                  mapView: this });
+                start = new TransitWalkMarker({ leg: leg,
+                                                previousLeg: previousLeg,
+                                                mapView: this });
             } else {
-                start = new TransitBoardMarker.TransitBoardMarker({ leg: leg,
-                                                                    mapView: this });
+                start = new TransitBoardMarker({ leg: leg,
+                                                 mapView: this });
             }
 
             this._instructionMarkerLayer.add_marker(start);
@@ -882,8 +857,8 @@ var MapView = GObject.registerClass({
 
         /* add arrival marker */
         let lastLeg = itinerary.legs.last();
-        let arrival = new TransitArrivalMarker.TransitArrivalMarker({ leg: lastLeg,
-                                                                      mapView: this });
+        let arrival = new TransitArrivalMarker({ leg: lastLeg,
+                                                 mapView: this });
         this._instructionMarkerLayer.add_marker(arrival);
 
         this.routingOpen = true;
@@ -907,4 +882,32 @@ var MapView = GObject.registerClass({
     onSetMarkerSelected(selectedMarker) {
         this.emit('marker-selected', selectedMarker);
     }
-});
+}
+
+GObject.registerClass({
+    Properties: {
+        // this property is true when the routing sidebar is active
+        'routingOpen': GObject.ParamSpec.boolean('routingOpen',
+                                                  'Routing open',
+                                                  'Routing sidebar open',
+                                                  GObject.ParamFlags.READABLE |
+                                                  GObject.ParamFlags.WRITABLE,
+                                                  false),
+        /* this property is true when a route is being shown on the map */
+        'routeShowing': GObject.ParamSpec.boolean('routeShowing',
+                                                 'Route showing',
+                                                 'Showing a route on the map',
+                                                 GObject.ParamFlags.READABLE |
+                                                 GObject.ParamFlags.WRITABLE,
+                                                 false)
+    },
+    Signals: {
+        'user-location-changed': {},
+        'going-to': {},
+        'going-to-user-location': {},
+        'gone-to-user-location': {},
+        'view-moved': {},
+        'marker-selected': { param_types: [Champlain.Marker] },
+        'map-type-changed': { param_types: [GObject.TYPE_STRING] }
+    },
+}, MapView);
diff --git a/src/mapWalker.js b/src/mapWalker.js
index dcef258c..925ea5bb 100644
--- a/src/mapWalker.js
+++ b/src/mapWalker.js
@@ -21,38 +21,34 @@
  *         Damián Nohales <damiannohales gmail com>
  */
 
-const Clutter = imports.gi.Clutter;
-const GObject = imports.gi.GObject;
+import Clutter from 'gi://Clutter';
+import GObject from 'gi://GObject';
 
-const BoundingBox = imports.boundingBox;
-const Location = imports.location;
-const PlaceZoom = imports.placeZoom;
-const Utils = imports.utils;
+import {BoundingBox} from './boundingBox.js';
+import {Location} from './location.js';
+import * as PlaceZoom from './placeZoom.js';
+import * as Utils from './utils.js';
 
 const _MAX_DISTANCE = 19850; // half of Earth's circumference (km)
 const _MIN_ANIMATION_DURATION = 2000; // msec
 const _MAX_ANIMATION_DURATION = 5000; // msec
 
-var MapWalker = GObject.registerClass({
-    Signals: {
-        'gone-to': { }
-    }
-}, class MapWalker extends GObject.Object {
+export class MapWalker extends GObject.Object {
 
-    _init(place, mapView) {
+    constructor(place, mapView) {
+        super();
         this.place = place;
         this._mapView = mapView;
         this._view = mapView.view;
         this._boundingBox = this._createBoundingBox(this.place);
-        super._init();
     }
 
     _createBoundingBox(place) {
         if (place.bounding_box !== null) {
-            return new BoundingBox.BoundingBox({ top: place.bounding_box.top,
-                                                 bottom: place.bounding_box.bottom,
-                                                 left: place.bounding_box.left,
-                                                 right: place.bounding_box.right });
+            return new BoundingBox({ top: place.bounding_box.top,
+                                     bottom: place.bounding_box.bottom,
+                                     left: place.bounding_box.left,
+                                     right: place.bounding_box.right });
         } else {
             return null;
         }
@@ -100,8 +96,8 @@ var MapWalker = GObject.registerClass({
             return;
         }
 
-        let fromLocation = new Location.Location({ latitude: this._view.get_center_latitude(),
-                                                   longitude: this._view.get_center_longitude() });
+        let fromLocation = new Location({ latitude: this._view.get_center_latitude(),
+                                          longitude: this._view.get_center_longitude() });
         this._updateGoToDuration(fromLocation);
 
         if (linear) {
@@ -143,10 +139,10 @@ var MapWalker = GObject.registerClass({
 
             visibleBox.extend(fromLocation.latitude, fromLocation.longitude);
         } else {
-            visibleBox = new BoundingBox.BoundingBox({ left:   180,
-                                                       right: -180,
-                                                       bottom:  90,
-                                                       top:    -90 });
+            visibleBox = new BoundingBox({ left:   180,
+                                           right: -180,
+                                           bottom:  90,
+                                           top:    -90 });
 
             [fromLocation, this.place.location].forEach((location) => {
                 visibleBox.left   = Math.min(visibleBox.left,   location.longitude);
@@ -195,4 +191,10 @@ var MapWalker = GObject.registerClass({
         // ensure_visible as 'goto' journeys with its own duration.
         this._view.goto_animation_duration = duration / 2;
     }
-});
+}
+
+GObject.registerClass({
+    Signals: {
+        'gone-to': { }
+    }
+}, MapWalker);
diff --git a/src/meson.build b/src/meson.build
index feaaad25..5ac721b4 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -23,6 +23,9 @@ configure_file(
 
 sources_conf = configuration_data()
 sources_conf.set('suffix', suffix)
+# comment-out test sources
+sources_conf.set('testopencomment', '<!--')
+sources_conf.set('testclosecomment', '-->')
 
 gnome.compile_resources(
        app_id + '.src',
diff --git a/src/org.gnome.Maps.in b/src/org.gnome.Maps.in
index 1cd74738..133656e8 100755
--- a/src/org.gnome.Maps.in
+++ b/src/org.gnome.Maps.in
@@ -1,5 +1,11 @@
 #!@GJS@
-imports.package.start({ name: "gnome-maps",
-                        version: "@PACKAGE_VERSION@",
-                        prefix: "@prefix@",
-                        libdir: "@libdir@" });
+imports.package.init({ name: "gnome-maps",
+                       version: "@PACKAGE_VERSION@",
+                       prefix: "@prefix@",
+                       libdir: "@libdir@" });
+
+import(`resource:///org/gnome/Maps@suffix@/js/main.js`).catch(error => {
+    console.error(error);
+    imports.system.exit(1);
+});
+
diff --git a/src/org.gnome.Maps.src.gresource.xml.in b/src/org.gnome.Maps.src.gresource.xml.in
index 1f3b93d7..72832808 100644
--- a/src/org.gnome.Maps.src.gresource.xml.in
+++ b/src/org.gnome.Maps.src.gresource.xml.in
@@ -116,5 +116,21 @@
     <file>transitplugins/opendataCH.js</file>
     <file>transitplugins/openTripPlanner.js</file>
     <file>transitplugins/resrobot.js</file>
+
+    <!-- Tests are compiled into the GResource when the comment open and close
+         are empty-->
+    @testopencomment@
+    <file alias="addressTest.js">../tests/addressTest.js</file>
+    <file alias="boundingBoxTest.js">../tests/boundingBoxTest.js</file>
+    <file alias="colorTest.js">../tests/colorTest.js</file>
+    <file alias="osmNamesTest.js">../tests/osmNamesTest.js</file>
+    <file alias="placeIconsTest.js">../tests/placeIconsTest.js</file>
+    <file alias="placeZoomTest.js">../tests/placeZoomTest.js</file>
+    <file alias="timeTest.js">../tests/timeTest.js</file>
+    <file alias="translationsTest.js">../tests/translationsTest.js</file>
+    <file alias="urisTest.js">../tests/urisTest.js</file>
+    <file alias="utilsTest.js">../tests/utilsTest.js</file>
+    <file alias="wikipediaTest.js">../tests/wikipediaTest.js</file>
+    @testclosecomment@
   </gresource>
 </gresources>
diff --git a/src/osmAccountDialog.js b/src/osmAccountDialog.js
index 21c63fe3..378960b8 100644
--- a/src/osmAccountDialog.js
+++ b/src/osmAccountDialog.js
@@ -20,37 +20,26 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Application = imports.application;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import * as Utils from './utils.js';
 
-var Response = {
-    SIGNED_IN: 0
-};
+export class OSMAccountDialog extends Gtk.Dialog {
 
-var OSMAccountDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-account-dialog.ui',
-    InternalChildren: ['stack',
-                       'signInButton',
-                       'signInSpinner',
-                       'verificationEntry',
-                       'verifyButton',
-                       'errorLabel',
-                       'signedInUserLabel',
-                       'signOutButton'],
-}, class OSMAccountDialog extends Gtk.Dialog {
+    static Response = { SIGNED_IN: 0 };
 
-    _init(params) {
+    constructor(params) {
         /* This is a construct-only property and cannot be set by GtkBuilder */
         params.use_header_bar = true;
 
-        this._closeOnSignIn = params.closeOnSignIn;
+        let closeOnSignIn = params.closeOnSignIn;
         delete params.closeOnSignIn;
 
-        super._init(params);
+        super(params);
 
+        this._closeOnSignIn = closeOnSignIn;
         this._signInButton.connect('clicked',
                                    this._onSignInButtonClicked.bind(this));
         this._verifyButton.connect('clicked',
@@ -174,4 +163,16 @@ var OSMAccountDialog = GObject.registerClass({
         this._signInButton.sensitive= true;
         this._stack.visible_child_name = 'sign-in';
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-account-dialog.ui',
+    InternalChildren: ['stack',
+                       'signInButton',
+                       'signInSpinner',
+                       'verificationEntry',
+                       'verifyButton',
+                       'errorLabel',
+                       'signedInUserLabel',
+                       'signOutButton'],
+}, OSMAccountDialog);
diff --git a/src/osmConnection.js b/src/osmConnection.js
index f20e8600..c61b505c 100644
--- a/src/osmConnection.js
+++ b/src/osmConnection.js
@@ -20,16 +20,18 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const Maps = imports.gi.GnomeMaps;
+import GnomeMaps from 'gi://GnomeMaps';
 
-const Gio = imports.gi.Gio;
-const Rest = imports.gi.Rest;
-const Secret = imports.gi.Secret;
-const Soup = imports.gi.Soup;
+import Gio from 'gi://Gio';
+import Rest from 'gi://Rest';
+import Secret from 'gi://Secret';
+import Soup from 'gi://Soup';
 
-const Utils = imports.utils;
+import * as Utils from './utils.js';
+
+const _ = gettext.gettext;
 
 const BASE_URL = 'https://api.openstreetmap.org/api';
 const API_VERSION = '0.6';
@@ -46,7 +48,7 @@ const SECRET_SCHEMA = new Secret.Schema("org.gnome.Maps",
     }
 );
 
-var OSMConnection = class OSMConnection {
+export class OSMConnection {
 
     constructor() {
         this._session = new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version });
@@ -55,7 +57,7 @@ var OSMConnection = class OSMConnection {
         this._callProxy = Rest.OAuthProxy.new(CONSUMER_KEY, CONSUMER_SECRET,
                                               BASE_URL + '/' + API_VERSION,
                                               false);
-        Maps.osm_init();
+        GnomeMaps.osm_init();
     }
 
     getOSMObject(type, id, callback, cancellable) {
@@ -74,8 +76,8 @@ var OSMConnection = class OSMConnection {
             }
 
             try {
-                let object = Maps.osm_parse (message.response_body.data,
-                                             message.response_body.length);
+                let object = GnomeMaps.osm_parse (message.response_body.data,
+                                                  message.response_body.length);
                 callback(true, message.status_code, object, type, null);
             } catch (e) {
                 Utils.debug(e);
@@ -121,10 +123,10 @@ var OSMConnection = class OSMConnection {
 
     _doOpenChangeset(comment, callback) {
         let changeset =
-            Maps.OSMChangeset.new(comment, 'gnome-maps ' + pkg.version);
+            GnomeMaps.OSMChangeset.new(comment, 'gnome-maps ' + pkg.version);
         let xml = changeset.serialize();
 
-        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
         call.set_method('PUT');
         call.set_function('/changeset/create');
 
@@ -146,7 +148,7 @@ var OSMConnection = class OSMConnection {
         object.changeset = changeset;
 
         let xml = object.serialize();
-        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
 
         call.set_method('PUT');
         call.set_function(this._getCreateOrUpdateFunction(object, type));
@@ -168,7 +170,7 @@ var OSMConnection = class OSMConnection {
         object.changeset = changeset;
 
         let xml = object.serialize();
-        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
 
         call.set_method('DELETE');
         call.set_function(this._getDeleteFunction(object, type));
@@ -274,7 +276,7 @@ var OSMConnection = class OSMConnection {
         switch (call.get_status_code()) {
             case Soup.Status.OK:
                 try {
-                    callback(Maps.osm_parse_user_details(call.get_payload()));
+                    callback(GnomeMaps.osm_parse_user_details(call.get_payload()));
                 } catch (e) {
                     Utils.debug('Error parsing user details: ' + e.message);
                     callback(null);
@@ -339,32 +341,32 @@ var OSMConnection = class OSMConnection {
     _onPasswordCleared(source, result) {
         Secret.password_clear_finish(result);
     }
-};
 
-/*
- * Gets a status message (usually for an error case)
- * to show for a given OSM server response.
- */
-function getStatusMessage(statusCode) {
-    switch (statusCode) {
-    case Soup.Status.IO_ERROR:
-    case Soup.Status.UNAUTHORIZED:
-        /* setting the status in session.cancel_message still seems
-           to always give status IO_ERROR */
-        return _("Incorrect user name or password");
-    case Soup.Status.OK:
-        return _("Success");
-    case Soup.Status.BAD_REQUEST:
-        return _("Bad request");
-    case Soup.Status.NOT_FOUND:
-        return _("Object not found");
-    case Soup.Status.CONFLICT:
-        return _("Conflict, someone else has just modified the object");
-    case Soup.Status.GONE:
-        return _("Object has been deleted");
-    case Soup.Status.PRECONDITION_FAILED:
-        return _("Way or relation refers to non-existing children");
-    default:
-        return null;
+    /*
+     * Gets a status message (usually for an error case)
+     * to show for a given OSM server response.
+     */
+    static getStatusMessage(statusCode) {
+        switch (statusCode) {
+        case Soup.Status.IO_ERROR:
+        case Soup.Status.UNAUTHORIZED:
+            /* setting the status in session.cancel_message still seems
+               to always give status IO_ERROR */
+            return _("Incorrect user name or password");
+        case Soup.Status.OK:
+            return _("Success");
+        case Soup.Status.BAD_REQUEST:
+            return _("Bad request");
+        case Soup.Status.NOT_FOUND:
+            return _("Object not found");
+        case Soup.Status.CONFLICT:
+            return _("Conflict, someone else has just modified the object");
+        case Soup.Status.GONE:
+            return _("Object has been deleted");
+        case Soup.Status.PRECONDITION_FAILED:
+            return _("Way or relation refers to non-existing children");
+        default:
+            return null;
+        }
     }
 }
diff --git a/src/osmEdit.js b/src/osmEdit.js
index bd3d6256..16f41741 100644
--- a/src/osmEdit.js
+++ b/src/osmEdit.js
@@ -20,19 +20,19 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Application = imports.application;
-const OSMAccountDialog = imports.osmAccountDialog;
-const OSMEditDialog = imports.osmEditDialog;
-const OSMConnection = imports.osmConnection;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import {OSMAccountDialog} from './osmAccountDialog.js';
+import {OSMEditDialog} from './osmEditDialog.js';
+import {OSMConnection} from './osmConnection.js';
+import * as Utils from './utils.js';
 
-/* minimum zoom level at which to offer adding a location */
-var MIN_ADD_LOCATION_ZOOM_LEVEL = 16;
+export class OSMEdit {
 
-var OSMEdit = class OSMEdit {
+    // minimum zoom level at which to offer adding a location
+    static get MIN_ADD_LOCATION_ZOOM_LEVEL() { return 16; }
 
     constructor() {
-        this._osmConnection = new OSMConnection.OSMConnection();
+        this._osmConnection = new OSMConnection();
         this._osmObject = null; // currently edited object
         this._username = Application.settings.get('osm-username');
         this._isSignedIn = this._username !== null && this._username.length > 0;
@@ -43,29 +43,25 @@ var OSMEdit = class OSMEdit {
     }
 
     createEditDialog(parentWindow, place) {
-        let dialog = new OSMEditDialog.OSMEditDialog({
-            transient_for: parentWindow,
-            modal: true,
-            place: place
-        });
+        let dialog = new OSMEditDialog({ transient_for: parentWindow,
+                                         modal: true,
+                                         place: place });
 
         return dialog;
     }
 
     createEditNewDialog(parentWindow, latitude, longitude) {
-        let dialog = new OSMEditDialog.OSMEditDialog({
-            transient_for: parentWindow,
-            modal: true,
-            addLocation: true,
-            latitude: latitude,
-            longitude: longitude
-        });
+        let dialog = new OSMEditDialog({ transient_for: parentWindow,
+                                         modal: true,
+                                         addLocation: true,
+                                         latitude: latitude,
+                                         longitude: longitude });
 
         return dialog;
     }
 
     createAccountDialog(parentWindow, closeOnSignIn) {
-        let dialog = new OSMAccountDialog.OSMAccountDialog({
+        let dialog = new OSMAccountDialog({
             transient_for: parentWindow,
             modal: true,
             closeOnSignIn: closeOnSignIn
@@ -191,4 +187,4 @@ var OSMEdit = class OSMEdit {
     get username() {
         return this._username;
     }
-};
+}
diff --git a/src/osmEditDialog.js b/src/osmEditDialog.js
index 7b28d051..d1601943 100644
--- a/src/osmEditDialog.js
+++ b/src/osmEditDialog.js
@@ -20,30 +20,25 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
-
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Soup = imports.gi.Soup;
-
-const Application = imports.application;
-const Maps = imports.gi.GnomeMaps;
-const OSMConnection = imports.osmConnection;
-const OSMTypes = imports.osmTypes;
-const OSMTypeSearchEntry = imports.osmTypeSearchEntry;
-const OSMUtils = imports.osmUtils;
-const Utils = imports.utils;
-const Wikipedia = imports.wikipedia;
-
-var Response = {
-    UPLOADED: 0,
-    DELETED: 1,
-    CANCELLED: 2,
-    ERROR: 3
-};
+import gettext from 'gettext';
+
+const _ = gettext.gettext;
+
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Soup from 'gi://Soup';
+
+import {Application} from './application.js';
+import GnomeMaps from 'gi://GnomeMaps';
+import {OSMConnection} from './osmConnection.js';
+import * as OSMTypes from './osmTypes.js';
+import {OSMTypeSearchEntry} from './osmTypeSearchEntry.js';
+import * as OSMUtils from './osmUtils.js';
+import * as Utils from './utils.js';
+import * as Wikipedia from './wikipedia.js';
 
 /*
  * enumeration representing
@@ -146,7 +141,7 @@ const OSM_FIELDS = [
         name: _("Phone"),
         tag: 'phone',
         type: EditFieldType.TEXT,
-        rewriteFunc: this._osmPhoneRewriteFunc,
+        rewriteFunc: _osmPhoneRewriteFunc,
         hint: _("Phone number. Use the international format, " +
                 "starting with a + sign. Beware of local privacy " +
                 "laws, especially for private phone numbers.")
@@ -156,7 +151,7 @@ const OSM_FIELDS = [
         tag: 'email',
         type: EditFieldType.TEXT,
         validate: Utils.isValidEmail,
-        rewriteFunc: this._osmEmailRewriteFunc,
+        rewriteFunc: _osmEmailRewriteFunc,
         validateError: _("This is not a valid e-mail address. Make sure to not include the mailto: protocol 
prefix."),
         hint: _("Contact e-mail address for inquiries. " +
                 "Add only email addresses that are intended to be publicly used.")
@@ -166,7 +161,7 @@ const OSM_FIELDS = [
         tag: 'wikipedia',
         type: EditFieldType.TEXT,
         validate: Wikipedia.isValidWikipedia,
-        rewriteFunc: this._osmWikipediaRewriteFunc,
+        rewriteFunc: _osmWikipediaRewriteFunc,
         hint: _("The format used should include the language code " +
                 "and the article title like “en:Article title”.")
     },
@@ -258,15 +253,9 @@ const OSM_FIELDS = [
         hint: _("Information used to inform other mappers about non-obvious information about an element, 
the author’s intent when creating it, or hints for further improvement.")
     }];
 
-const OSMEditAddress = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-edit-address.ui',
-    Children: [ 'street',
-                'number',
-                'post',
-                'city' ],
-}, class OSMEditAddress extends Gtk.Grid {
+export class OSMEditAddress extends Gtk.Grid {
 
-    _init(params) {
+    constructor(params) {
         let street = params.street;
         delete params.street;
 
@@ -279,7 +268,7 @@ const OSMEditAddress = GObject.registerClass({
         let city = params.city;
         delete params.city;
 
-        super._init(params);
+        super(params);
 
         if (street)
             this.street.text = street;
@@ -293,52 +282,47 @@ const OSMEditAddress = GObject.registerClass({
         if (city)
             this.city.text = city;
     }
-});
+}
 
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-edit-address.ui',
+    Children: [ 'street',
+                'number',
+                'post',
+                'city' ],
+}, OSMEditAddress);
 
-var OSMEditDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-edit-dialog.ui',
-    InternalChildren: [ 'cancelButton',
-                        'backButton',
-                        'nextButton',
-                        'stack',
-                        'editorGrid',
-                        'commentTextView',
-                        'addFieldPopoverGrid',
-                        'addFieldButton',
-                        'typeSearchGrid',
-                        'typeLabel',
-                        'typeButton',
-                        'typeValueLabel',
-                        'recentTypesLabel',
-                        'recentTypesListBox',
-                        'hintPopover',
-                        'hintLabel',
-                        'headerBar'],
-}, class OSMEditDialog extends Gtk.Dialog {
+export class OSMEditDialog extends Gtk.Dialog {
 
-    _init(params) {
-        this._place = params.place;
+    static Response = {
+        UPLOADED: 0,
+        DELETED: 1,
+        CANCELLED: 2,
+        ERROR: 3
+    };
+
+    constructor(params) {
+        let place = params.place;
         delete params.place;
 
-        this._addLocation = params.addLocation;
+        let addLocation = params.addLocation;
         delete params.addLocation;
 
-        this._latitude = params.latitude;
+        let latitude = params.latitude;
         delete params.latitude;
 
-        this._longitude = params.longitude;
+        let longitude = params.longitude;
         delete params.longitude;
 
         /* This is a construct-only property and cannot be set by GtkBuilder */
         params.use_header_bar = true;
 
-        super._init(params);
+        super(params);
 
         /* I could not get this widget working from within the widget template
          * this results in a segfault. The widget definition is left in-place,
          * but commented-out in the template file */
-        this._typeSearch = new OSMTypeSearchEntry.OSMTypeSearchEntry();
+        this._typeSearch = new OSMTypeSearchEntry();
         this._typeSearchGrid.attach(this._typeSearch, 0, 0, 1, 1);
         this._typeSearch.visible = true;
         this._typeSearch.can_focus = true;
@@ -359,23 +343,23 @@ var OSMEditDialog = GObject.registerClass({
         this._backButton.connect('clicked', () => this._onBackClicked());
         this._typeButton.connect('clicked', () => this._onTypeClicked());
 
-        if (this._addLocation) {
+        if (addLocation) {
             this._headerBar.title = C_("dialog title", "Add to OpenStreetMap");
             this._typeLabel.visible = true;
             this._typeButton.visible = true;
 
             /* the OSMObject ID, version, and changeset ID is unknown for now */
             let newNode =
-                Maps.OSMNode.new(0, 0, 0, this._longitude, this._latitude);
+                GnomeMaps.OSMNode.new(0, 0, 0, longitude, latitude);
             /* set a placeholder name tag to always get a name entry for new
              * locations */
             newNode.set_tag('name', '');
             this._loadOSMData(newNode);
             this._isEditing = true;
-            this._osmType = Geocode.PlaceOsmType.NODE;
+            this._osmType = GeocodeGlib.PlaceOsmType.NODE;
         } else {
-            this._osmType = this._place.osmType;
-            Application.osmEdit.fetchObject(this._place,
+            this._osmType = place.osmType;
+            Application.osmEdit.fetchObject(place,
                                             this._onObjectFetched.bind(this),
                                             this._cancellable);
         }
@@ -540,7 +524,7 @@ var OSMEditDialog = GObject.registerClass({
     }
 
     _onCancelClicked() {
-        this.response(Response.CANCELLED);
+        this.response(OSMEditDialog.Response.CANCELLED);
     }
 
     _onBackClicked() {
@@ -566,7 +550,7 @@ var OSMEditDialog = GObject.registerClass({
 
     _onObjectUploaded(success, status) {
         if (success) {
-            this.response(Response.UPLOADED);
+            this.response(OSMEditDialog.Response.UPLOADED);
         } else {
             this._showError(status);
             this.response(Response.ERROR);
@@ -904,4 +888,25 @@ var OSMEditDialog = GObject.registerClass({
         this._updateTypeButton();
         this._stack.visible_child_name = 'editor';
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-edit-dialog.ui',
+    InternalChildren: [ 'cancelButton',
+                        'backButton',
+                        'nextButton',
+                        'stack',
+                        'editorGrid',
+                        'commentTextView',
+                        'addFieldPopoverGrid',
+                        'addFieldButton',
+                        'typeSearchGrid',
+                        'typeLabel',
+                        'typeButton',
+                        'typeValueLabel',
+                        'recentTypesLabel',
+                        'recentTypesListBox',
+                        'hintPopover',
+                        'hintLabel',
+                        'headerBar'],
+}, OSMEditDialog);
diff --git a/src/osmNames.js b/src/osmNames.js
index 97ac4613..4162134e 100644
--- a/src/osmNames.js
+++ b/src/osmNames.js
@@ -24,7 +24,7 @@
  * See https://wiki.openstreetmap.org/wiki/Multilingual_names
  */
 
-const Utils = imports.utils
+import * as Utils from './utils.js';
 
 /**
  * Mapping writing systems (scripts) to languages (most commonly
@@ -138,7 +138,7 @@ const WRITING_SYSTEMS = [
     }
 ];
 
-function getNameForLanguageAndCountry(tags, language, country) {
+export function getNameForLanguageAndCountry(tags, language, country) {
     let localizedName = _getNameInLanguage(tags, language);
 
     /* for names in Norwegian, the best practice in OSM is to use the
@@ -154,7 +154,7 @@ function getNameForLanguageAndCountry(tags, language, country) {
                                                                  country);
 }
 
-function _getFallbackNameForLanguageAndCountry(tags, language, country) {
+export function _getFallbackNameForLanguageAndCountry(tags, language, country) {
     let intName;
 
     if (_predominantWritingSystemMatchesLanguage(country, language) && tags.name)
diff --git a/src/osmTypeListRow.js b/src/osmTypeListRow.js
index 795d203c..84bb0c48 100644
--- a/src/osmTypeListRow.js
+++ b/src/osmTypeListRow.js
@@ -19,19 +19,16 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-var OSMTypeListRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-type-list-row.ui',
-    InternalChildren: [ 'name' ]
-}, class OSMTypeListRow extends Gtk.ListBoxRow {
+export class OSMTypeListRow extends Gtk.ListBoxRow {
 
-    _init(props) {
+    constructor(props) {
         this._type = props.type;
         delete props.type;
 
-        super._init(props);
+        super(props);
 
         this._name.label = this._type.title;
     }
@@ -47,4 +44,9 @@ var OSMTypeListRow = GObject.registerClass({
     get title() {
         return this._type.title;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-type-list-row.ui',
+    InternalChildren: [ 'name' ]
+}, OSMTypeListRow);
diff --git a/src/osmTypePopover.js b/src/osmTypePopover.js
index 664ae721..5a3d30e2 100644
--- a/src/osmTypePopover.js
+++ b/src/osmTypePopover.js
@@ -19,26 +19,16 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const OSMTypeListRow = imports.osmTypeListRow;
-const SearchPopover = imports.searchPopover;
+import {OSMTypeListRow} from './osmTypeListRow.js';
+import {SearchPopover} from './searchPopover.js';
 
-var OSMTypePopover = GObject.registerClass({
-    InternalChildren: ['list'],
-    Template: 'resource:///org/gnome/Maps/ui/osm-type-popover.ui',
-    Signals : {
-        /* signal emitted when selecting a type, indicates OSM key and value
-         * and display title */
-        'selected' : { param_types: [ GObject.TYPE_STRING,
-                                      GObject.TYPE_STRING,
-                                      GObject.TYPE_STRING ] }
-    }
-}, class OSMTypePopover extends SearchPopover.SearchPopover {
+export class OSMTypePopover extends SearchPopover {
 
-    _init(props) {
-        super._init(props);
+    constructor(props) {
+        super(props);
 
         this._list.connect('row-activated', (list, row) => {
             if (row)
@@ -54,8 +44,20 @@ var OSMTypePopover = GObject.registerClass({
     }
 
     _addRow(type) {
-        let row = new OSMTypeListRow.OSMTypeListRow({ type: type,
-                                                      can_focus: true });
+        let row = new OSMTypeListRow({ type: type, can_focus: true });
+
         this._list.insert(row, -1);
     }
-});
+}
+
+GObject.registerClass({
+    InternalChildren: ['list'],
+    Template: 'resource:///org/gnome/Maps/ui/osm-type-popover.ui',
+    Signals : {
+        /* signal emitted when selecting a type, indicates OSM key and value
+         * and display title */
+        'selected' : { param_types: [ GObject.TYPE_STRING,
+                                      GObject.TYPE_STRING,
+                                      GObject.TYPE_STRING ] }
+    }
+}, OSMTypePopover);
diff --git a/src/osmTypeSearchEntry.js b/src/osmTypeSearchEntry.js
index eae92355..74ee6544 100644
--- a/src/osmTypeSearchEntry.js
+++ b/src/osmTypeSearchEntry.js
@@ -19,24 +19,21 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const OSMTypePopover = imports.osmTypePopover;
-const OSMTypes = imports.osmTypes;
-const Utils = imports.utils;
+import {OSMTypePopover} from './osmTypePopover.js';
+import * as OSMTypes from './osmTypes.js';
+import * as Utils from './utils.js';
 
 const MAX_MATCHES = 10;
 
-var OSMTypeSearchEntry = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-type-search-entry.ui'
-}, class OSMTypeSearchEntry extends Gtk.SearchEntry {
+export class OSMTypeSearchEntry extends Gtk.SearchEntry {
 
-    _init(props) {
-        super._init(props);
+    constructor(props) {
+        super(props);
 
-        this._popover =
-            new OSMTypePopover.OSMTypePopover({relative_to: this});
+        this._popover = new OSMTypePopover({relative_to: this});
 
         this.connect('size-allocate', (widget, allocation) => {
             /* Magic number to make the alignment pixel perfect. */
@@ -72,4 +69,8 @@ var OSMTypeSearchEntry = GObject.registerClass({
             }
         }
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-type-search-entry.ui'
+}, OSMTypeSearchEntry);
diff --git a/src/osmTypes.js b/src/osmTypes.js
index aa7d7c68..7609521e 100644
--- a/src/osmTypes.js
+++ b/src/osmTypes.js
@@ -19,10 +19,10 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
 
-const Utils = imports.utils;
+import * as Utils from './utils.js';
 
 const _RECENT_TYPES_STORE_FILE = 'maps-recent-types.json';
 const _NUM_RECENT_TYPES = 10;
@@ -32,7 +32,7 @@ const [_status, _buffer] = _file.load_contents(null);
 const OSM_TYPE_MAP = JSON.parse(Utils.getBufferText(_buffer));
 
 /* Lists the OSM tags we base our notion of location types on */
-var OSM_TYPE_TAGS = ['aeroway', 'amenity', 'leisure', 'office', 'place', 'shop', 'tourism' ];
+export const OSM_TYPE_TAGS = ['aeroway', 'amenity', 'leisure', 'office', 'place', 'shop', 'tourism' ];
 
 /* Sort function comparing two type values according to the locale-specific
  * comparison of the type title */
@@ -66,7 +66,7 @@ function _lookupTitle(item) {
     return null;
 }
 
-function findMatches(prefix, maxMatches) {
+export function findMatches(prefix, maxMatches) {
     let numMatches = 0;
     let prefixLength = prefix.length;
     let normalized = prefix.toLocaleLowerCase();
@@ -94,7 +94,7 @@ function findMatches(prefix, maxMatches) {
 }
 
 /* return the title of a type with a given key/value if it is known by us */
-function lookupType(key, value) {
+export function lookupType(key, value) {
     let item = OSM_TYPE_MAP[key + '/' + value];
 
     if (item) {
@@ -104,7 +104,7 @@ function lookupType(key, value) {
         return null;
 }
 
-var RecentTypesStore = class RecentTypesStore {
+export class RecentTypesStore {
 
     constructor() {
         this._filename = GLib.build_filenamev([GLib.get_user_data_dir(),
@@ -162,4 +162,4 @@ var RecentTypesStore = class RecentTypesStore {
     }
 };
 
-var recentTypesStore = new RecentTypesStore();
+export const recentTypesStore = new RecentTypesStore();
diff --git a/src/osmUtils.js b/src/osmUtils.js
index 866d063f..5b8f8315 100644
--- a/src/osmUtils.js
+++ b/src/osmUtils.js
@@ -20,15 +20,15 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Soup = imports.gi.Soup;
+import Soup from 'gi://Soup';
 
-const Application = imports.application;
+import {Application} from './application.js';
 
 /*
  * Gets a Wikipedia article in OSM tag format (i.e. lang:Article title)
  * given a URL or null if input doesn't match a Wikipedia URL
  */
-function getWikipediaOSMArticleFormatFromUrl(url) {
+export function getWikipediaOSMArticleFormatFromUrl(url) {
     let regex = /https?:\/\/(..)\.wikipedia\.org\/wiki\/(.+)/;
     let match = url.match(regex);
 
@@ -46,7 +46,7 @@ function getWikipediaOSMArticleFormatFromUrl(url) {
  * Updates a Place object according to an OSMObject.
  * Will also update place in the place store.
  */
-function updatePlaceFromOSMObject(place, object) {
+export function updatePlaceFromOSMObject(place, object) {
     let name = object.get_tag('name');
 
     if (name) {
diff --git a/src/overpass.js b/src/overpass.js
index 2265f24c..eb561c1f 100644
--- a/src/overpass.js
+++ b/src/overpass.js
@@ -18,14 +18,15 @@
  */
 
 const Format = imports.format;
-const Geocode = imports.gi.GeocodeGlib;
-const GObject = imports.gi.GObject;
-const Soup = imports.gi.Soup;
 
-const OSMNames = imports.osmNames;
-const PhotonParser = imports.photonParser;
-const Place = imports.place;
-const Utils = imports.utils;
+import Geocode from 'gi://GeocodeGlib';
+import GObject from 'gi://GObject';
+import Soup from 'gi://Soup';
+
+import * as OSMNames from './osmNames.js';
+import * as PhotonParser from './photonParser.js';
+import {Place} from './place.js';
+import * as Utils from './utils.js';
 
 const _DEFAULT_TIMEOUT = 180;
 const _DEFAULT_MAXSIZE = 536870912;
@@ -36,21 +37,12 @@ const _DEFAULT_OUTPUT_SORT_ORDER = 'qt';
 
 const BASE_URL = 'https://overpass-api.de/api/interpreter';
 
-var Overpass = GObject.registerClass({
-    Properties: {
-        'place': GObject.ParamSpec.object('place',
-                                          'Place',
-                                          'Place with added information',
-                                          GObject.ParamFlags.READABLE |
-                                          GObject.ParamFlags.WRITABLE,
-                                          Geocode.Place)
-    }
-}, class Overpass extends GObject.Object {
+export class Overpass extends GObject.Object {
 
-    _init(params) {
+    constructor(params) {
         params = params || { };
 
-        super._init();
+        super();
 
         // maximum allowed runtime for the query in seconds
         this.timeout = params.timeout || _DEFAULT_TIMEOUT;
@@ -249,4 +241,16 @@ var Overpass = GObject.registerClass({
                                                        this.outputSortOrder,
                                                        this.outputCount ]);
     }
-});
+}
+
+GObject.registerClass({
+    Properties: {
+        'place': GObject.ParamSpec.object('place',
+                                          'Place',
+                                          'Place with added information',
+                                          GObject.ParamFlags.READABLE |
+                                          GObject.ParamFlags.WRITABLE,
+                                          Geocode.Place)
+    }},
+    Overpass
+);
diff --git a/src/photonGeocode.js b/src/photonGeocode.js
index 38d88ca2..159db1f1 100644
--- a/src/photonGeocode.js
+++ b/src/photonGeocode.js
@@ -21,19 +21,19 @@
 
 const Format = imports.format;
 
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
-const Application = imports.application;
-const HTTP = imports.http;
-const PhotonParser = imports.photonParser;
-const Service = imports.service;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import * as HTTP from './http.js';
+import * as PhotonParser from './photonParser.js';
+import * as Service from './service.js';
+import * as Utils from './utils.js';
 
 // HTTP session timeout (in seconds)
 const TIMEOUT = 5;
 
-var PhotonGeocode = class {
+export class PhotonGeocode {
     constructor() {
         this._session =
             new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version,
diff --git a/src/photonParser.js b/src/photonParser.js
index 041b7734..8d006a61 100644
--- a/src/photonParser.js
+++ b/src/photonParser.js
@@ -19,17 +19,19 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const Geocode = imports.gi.GeocodeGlib;
+import GeocodeGlib from 'gi://GeocodeGlib';
 
-const Address = imports.address;
-const OSMTypes = imports.osmTypes;
-const Place = imports.place;
-const Utils = imports.utils;
+import * as Address from './address.js';
+import * as OSMTypes from './osmTypes.js';
+import {Place} from './place.js';
+import * as Utils from './utils.js';
 
-function parsePlace(latitude, longitude, properties) {
-    let location = new Geocode.Location({ latitude:  latitude,
+const _ = gettext.gettext;
+
+export function parsePlace(latitude, longitude, properties) {
+    let location = new GeocodeGlib.Location({ latitude:  latitude,
                                           longitude: longitude,
                                           accuracy:  0.0 });
     let type = _parsePlaceType(properties);
@@ -92,7 +94,7 @@ function parsePlace(latitude, longitude, properties) {
     if (properties.osm_value)
         params.osmValue = properties.osm_value;
 
-    return new Place.Place(params);
+    return new Place(params);
 }
 
 function _parseName(properties) {
@@ -114,19 +116,19 @@ function _parseName(properties) {
 function _parseOsmType(osmType) {
     switch (osmType) {
         case 'N':
-            return Geocode.PlaceOsmType.NODE;
+            return GeocodeGlib.PlaceOsmType.NODE;
         case 'W':
-            return Geocode.PlaceOsmType.WAY;
+            return GeocodeGlib.PlaceOsmType.WAY;
         case 'R':
-            return Geocode.PlaceOsmType.RELATION;
+            return GeocodeGlib.PlaceOsmType.RELATION;
         default:
-            return Geocode.PlaceOsmType.UNKNOWN;
+            return GeocodeGlib.PlaceOsmType.UNKNOWN;
     }
 }
 
 function _parsePlaceType(properties) {
     if (!properties)
-        return Geocode.PlaceType.UNKNOWN;
+        return GeocodeGlib.PlaceType.UNKNOWN;
 
     let key = properties.osm_key;
     let value = properties.osm_value;
@@ -135,82 +137,82 @@ function _parsePlaceType(properties) {
         case 'place':
             switch (value) {
                 case 'continent':
-                    return Geocode.PlaceType.CONTINENT;
+                    return GeocodeGlib.PlaceType.CONTINENT;
                 case 'country':
-                    return Geocode.PlaceType.COUNTRY;
+                    return GeocodeGlib.PlaceType.COUNTRY;
                 case 'city':
                 case 'town':
                 case 'village':
                 case 'hamlet':
-                    return Geocode.PlaceType.TOWN;
+                    return GeocodeGlib.PlaceType.TOWN;
                 case 'suburb':
-                    return Geocode.PlaceType.SUBURB;
+                    return GeocodeGlib.PlaceType.SUBURB;
                 case 'house':
-                    return Geocode.PlaceType.BUILDING;
+                    return GeocodeGlib.PlaceType.BUILDING;
                 case 'island':
-                    return Geocode.PlaceType.ISLAND;
+                    return GeocodeGlib.PlaceType.ISLAND;
                 case 'municipality':
-                    return Geocode.PlaceType.COUNTY;
+                    return GeocodeGlib.PlaceType.COUNTY;
                 default:
-                    return Geocode.PlaceType.MISCELLANEOUS;
+                    return GeocodeGlib.PlaceType.MISCELLANEOUS;
             }
         case 'amenity':
             switch (value) {
                 case 'bar':
                 case 'pub':
                 case 'nightclub':
-                    return Geocode.PlaceType.BAR;
+                    return GeocodeGlib.PlaceType.BAR;
                 case 'restaurant':
                 case 'fast_food':
-                    return Geocode.PlaceType.RESTAURANT;
+                    return GeocodeGlib.PlaceType.RESTAURANT;
                 case 'school':
                 case 'kindergarten':
-                    return Geocode.PlaceType.SCHOOL;
+                    return GeocodeGlib.PlaceType.SCHOOL;
                 case 'place_of_worship':
-                    return Geocode.PlaceType.PLACE_OF_WORSHIP;
+                    return GeocodeGlib.PlaceType.PLACE_OF_WORSHIP;
                 case 'bus_station':
-                    return Geocode.PlaceType.BUS_STOP;
+                    return GeocodeGlib.PlaceType.BUS_STOP;
                 default:
-                    return Geocode.PlaceType.MISCELLANEOUS;
+                    return GeocodeGlib.PlaceType.MISCELLANEOUS;
             }
         case 'highway':
             switch (value) {
                 case 'bus_stop':
-                    return Geocode.PlaceType.BUS_STOP;
+                    return GeocodeGlib.PlaceType.BUS_STOP;
                 case 'motorway':
-                    return Geocode.PlaceType.MOTORWAY;
+                    return GeocodeGlib.PlaceType.MOTORWAY;
                 default:
-                    return Geocode.PlaceType.STREET;
+                    return GeocodeGlib.PlaceType.STREET;
             }
         case 'railway':
             switch (value) {
                 case 'station':
                 case 'stop':
                 case 'halt':
-                    return Geocode.PlaceType.RAILWAY_STATION;
+                    return GeocodeGlib.PlaceType.RAILWAY_STATION;
                 case 'tram_stop':
-                    return Geocode.PlaceType.LIGHT_RAIL_STATION;
+                    return GeocodeGlib.PlaceType.LIGHT_RAIL_STATION;
                 default:
-                    return Geocode.PlaceType.MISCELLANEOUS;
+                    return GeocodeGlib.PlaceType.MISCELLANEOUS;
             }
         case 'aeroway':
             switch (value) {
                 case 'aerodrome':
-                    return Geocode.PlaceType.AIRPORT;
+                    return GeocodeGlib.PlaceType.AIRPORT;
                 default:
-                    return Geocode.PlaceType.MISCELLANEOUS;
+                    return GeocodeGlib.PlaceType.MISCELLANEOUS;
             }
         case 'building':
             switch (value) {
                 case 'yes':
-                    return Geocode.PlaceType.BUILDING;
+                    return GeocodeGlib.PlaceType.BUILDING;
                 case 'railway_station':
-                    return Geocode.PlaceType.RAILWAY_STATION;
+                    return GeocodeGlib.PlaceType.RAILWAY_STATION;
                 default:
-                    return Geocode.PlaceType.MISCELLANEOUS;
+                    return GeocodeGlib.PlaceType.MISCELLANEOUS;
             }
         default:
-            return Geocode.PlaceType.MISCELLANEOUS;
+            return GeocodeGlib.PlaceType.MISCELLANEOUS;
     }
 }
 
@@ -226,10 +228,10 @@ function _parseBoundingBox(extent) {
     /* it seems GraphHopper geocode swaps order of bottom and top compared
      * to stock Photon, so just in case "clamp" both pairs
      */
-    return new Geocode.BoundingBox({ left:   Math.min(extent[0], extent[2]),
-                                     bottom: Math.min(extent[1], extent[3]),
-                                     right:  Math.max(extent[0], extent[2]),
-                                     top:    Math.max(extent[1], extent[3]) });
+    return new GeocodeGlib.BoundingBox({ left:   Math.min(extent[0], extent[2]),
+                                         bottom: Math.min(extent[1], extent[3]),
+                                         right:  Math.max(extent[0], extent[2]),
+                                         top:    Math.max(extent[1], extent[3]) });
 }
 
 /* check if an extent value is a valid latitude (clamp to the maximum latitude
diff --git a/src/place.js b/src/place.js
index b772a46c..f16eee5d 100644
--- a/src/place.js
+++ b/src/place.js
@@ -19,18 +19,20 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
 
-const Location = imports.location;
-const Overpass = imports.overpass;
-const PlaceIcons = imports.placeIcons;
-const URIS = imports.uris;
-const Utils = imports.utils;
+import {Location} from './location.js';
+import {Overpass} from './overpass.js';
+import * as PlaceIcons from './placeIcons.js';
+import * as URIS from './uris.js';
+import * as Utils from './utils.js';
+
+const _ = gettext.gettext;
 
 // Matches coordinates string in 'Decimal Degrees' format
 const DECIMAL_COORDINATES_REGEX = (
@@ -44,11 +46,12 @@ const DMS_COORDINATES_REGEX = new RegExp(
     "i"
 );
 
-var Place = GObject.registerClass(
-class Place extends Geocode.Place {
+export class Place extends GeocodeGlib.Place {
+
+    constructor(params) {
+        let originalParams = {};
 
-    _init(params) {
-        this.updateFromTags(params);
+        Object.assign(originalParams, params);
 
         delete params.population;
         delete params.website;
@@ -60,64 +63,62 @@ class Place extends Geocode.Place {
         delete params.religion;
         delete params.takeaway;
         delete params.note;
-
-        this._isCurrentLocation = params.isCurrentLocation;
         delete params.isCurrentLocation;
-
-        this._initialZoom = params.initialZoom;
         delete params.initialZoom;
-
-        /* set to true if the instance is pre-filled with Overpass data,
-         * at the time of creation, as will be the case when loading a place
-         * from an OSM object URL
-         */
-        this._prefilled = params.prefilled;
         delete params.prefilled;
-
-        /* Determines if the place should be added to the place store */
-        if (typeof(params.store) === 'undefined') {
-            this._store = true;
-        } else {
-            this._store = params.store;
-            delete params.store;
-        }
-
+        delete params.store;
         delete params.wheelchair;
-
-        this._nativeName = params.nativeName;
         delete params.nativeName;
-
-        this._osmKey = params.osmKey;
         delete params.osmKey;
-
-        this._osmValue = params.osmValue;
         delete params.osmValue;
 
-        if (params.place) {
-            params = { osm_id: params.place.osm_id,
-                       osm_type: params.place.osm_type,
-                       name: params.place.name,
-                       location: params.place.location,
-                       bounding_box: params.place.bounding_box,
-                       place_type: params.place.place_type,
-                       street_address: params.place.street_address,
-                       street: params.place.street,
-                       building: params.place.building,
-                       postal_code: params.place.postal_code,
-                       area: params.place.area,
-                       town: params.place.town,
-                       state: params.place.state,
-                       county: params.place.county,
-                       country: params.place.country,
-                       country_code: params.place.country_code,
-                       continent: params.place.continent };
+        if (originalParams.place) {
+            params = { osm_id: originalParams.place.osm_id,
+                       osm_type: originalParams.place.osm_type,
+                       name: originalParams.place.name,
+                       location: originalParams.place.location,
+                       bounding_box: originalParams.place.bounding_box,
+                       place_type: originalParams.place.place_type,
+                       street_address: originalParams.place.street_address,
+                       street: originalParams.place.street,
+                       building: originalParams.place.building,
+                       postal_code: originalParams.place.postal_code,
+                       area: originalParams.place.area,
+                       town: originalParams.place.town,
+                       state: originalParams.place.state,
+                       county: originalParams.place.county,
+                       country: originalParams.place.country,
+                       country_code: originalParams.place.country_code,
+                       continent: originalParams.place.continent };
         }
 
         for (let prop in params)
             if (!params[prop])
                 delete params[prop];
 
-        super._init(params);
+        super(params);
+
+        this.updateFromTags(originalParams);
+
+        this._isCurrentLocation = originalParams.isCurrentLocation;
+        this._initialZoom = originalParams.initialZoom;
+
+        /* set to true if the instance is pre-filled with Overpass data,
+         * at the time of creation, as will be the case when loading a place
+         * from an OSM object URL
+         */
+        this._prefilled = originalParams.prefilled;
+
+        /* Determines if the place should be added to the place store */
+        if (typeof(originalParams.store) === 'undefined') {
+            this._store = true;
+        } else {
+            this._store = originalParams.store;
+        }
+
+        this._nativeName = originalParams.nativeName;
+        this._osmKey = originalParams.osmKey;
+        this._osmValue = originalParams.osmValue;
     }
 
     /**
@@ -409,100 +410,105 @@ class Place extends Geocode.Place {
             return false;
         }
     }
-});
 
-Place.fromJSON = function(obj) {
-    let props = { };
+    static fromJSON(obj) {
+        let props = { };
 
-    for (let key in obj) {
-        let prop = obj[key];
+        for (let key in obj) {
+            let prop = obj[key];
 
-        switch(key) {
-            case 'id':
-                props.osm_id = prop;
-                break;
+            switch(key) {
+                case 'id':
+                    props.osm_id = prop;
+                    break;
 
-            case 'location':
-                props.location = new Location.Location(prop);
-                break;
+                case 'location':
+                    props.location = new Location(prop);
+                    break;
 
-            case 'bounding_box':
-                if (prop)
-                    props.bounding_box = new Geocode.BoundingBox(prop);
-                break;
+                case 'bounding_box':
+                    if (prop)
+                        props.bounding_box = new GeocodeGlib.BoundingBox(prop);
+                    break;
 
-            default:
-                if (prop !== null && prop !== undefined)
-                    props[key] = prop;
-                break;
+                default:
+                    if (prop !== null && prop !== undefined)
+                        props[key] = prop;
+                    break;
+            }
         }
+        return new Place(props);
     }
-    return new Place(props);
-};
 
-Place.validateCoordinates = function(lat, lon) {
-    return lat <= 90 && lat >= -90 && lon <= 180 && lon >= -180;
-};
+    static validateCoordinates(lat, lon) {
+        return lat <= 90 && lat >= -90 && lon <= 180 && lon >= -180;
+    }
 
-Place.parseDecimalCoordinates = function(text) {
-    let match = text.match(DECIMAL_COORDINATES_REGEX);
+    static parseDecimalCoordinates(text) {
+        let match = text.match(DECIMAL_COORDINATES_REGEX);
 
-    if (match) {
-        let latitude = parseFloat(match[1]);
-        let longitude = parseFloat(match[2]);
+        if (match) {
+            let latitude = parseFloat(match[1]);
+            let longitude = parseFloat(match[2]);
 
-        return [latitude, longitude];
-    } else {
-        return null;
+            return [latitude, longitude];
+        } else {
+            return null;
+        }
     }
-};
 
-Place.parseDmsCoordinates = function(text) {
-    let match = text.match(DMS_COORDINATES_REGEX);
+    static parseDmsCoordinates(text) {
+        let match = text.match(DMS_COORDINATES_REGEX);
 
-    if (match) {
-        let degrees = parseFloat(match[1]);
-        let minutes = parseFloat(match[2]);
-        let seconds = parseFloat(match[3]);
-        let latitude = degrees + minutes / 60 + seconds / 3600;
+        if (match) {
+            let degrees = parseFloat(match[1]);
+            let minutes = parseFloat(match[2]);
+            let seconds = parseFloat(match[3]);
+            let latitude = degrees + minutes / 60 + seconds / 3600;
 
-        if (match[4].toUpperCase() === "S")
-            latitude *= -1;
+            if (match[4].toUpperCase() === "S")
+                latitude *= -1;
 
-        degrees = parseFloat(match[5]);
-        minutes = parseFloat(match[6]);
-        seconds = parseFloat(match[7]);
-        let longitude = degrees + minutes / 60 + seconds / 3600;
+            degrees = parseFloat(match[5]);
+            minutes = parseFloat(match[6]);
+            seconds = parseFloat(match[7]);
+            let longitude = degrees + minutes / 60 + seconds / 3600;
 
-        if (match[8].toUpperCase() === "W")
-            longitude *= -1;
+            if (match[8].toUpperCase() === "W")
+                longitude *= -1;
 
-        return [latitude, longitude];
-    } else {
-        return null;
-    }
-};
+            return [latitude, longitude];
+        } else {
+            return null;
+        }
+    };
 
-Place.parseCoordinates = function(text) {
-    let coords = Place.parseDecimalCoordinates(text) ||
-        Place.parseDmsCoordinates(text);
+    static parseCoordinates(text) {
+        let coords = Place.parseDecimalCoordinates(text) ||
+            Place.parseDmsCoordinates(text);
 
-    if (coords && Place.validateCoordinates(coords[0], coords[1])) {
-        return new Location.Location({ latitude: coords[0],
-                                       longitude: coords[1] });
-    } else {
-        return null;
+        if (coords && Place.validateCoordinates(coords[0], coords[1])) {
+            return new Location({ latitude: coords[0], longitude: coords[1] });
+        } else {
+            return null;
+        }
+    }
+
+    static parseHttpURL(text, callback) {
+        _parseHttpURL(text, callback);
     }
-};
+}
+
+GObject.registerClass(Place);
 
 let overpass = null;
 
 /* we can't import Application before the Place class has been defined
  * since it's used via PlaceStore
  */
-const Application = imports.application;
+import {Application} from './application.js';
 
-function parseHttpURL(text, callback) {
+function _parseHttpURL(text, callback) {
     let [type, id] = URIS.parseAsObjectURL(text);
 
     if (type && id) {
@@ -514,7 +520,7 @@ function parseHttpURL(text, callback) {
         }
 
         if (overpass === null)
-            overpass = new Overpass.Overpass();
+            overpass = new Overpass();
 
         Application.application.mark_busy();
         overpass.fetchPlace(type, id, (place) => {
@@ -531,7 +537,7 @@ function parseHttpURL(text, callback) {
             if (!Place.validateCoordinates(lat, lon)) {
                 callback(null, _("Coordinates in URL are not valid"));
             } else {
-                let location = new Location.Location({ latitude: lat, longitude: lon });
+                let location = new Location({ latitude: lat, longitude: lon });
                 let place = zoom ? new Place({ location: location, initialZoom: zoom }) :
                                    new Place({ location: location });
 
diff --git a/src/placeBar.js b/src/placeBar.js
index 0cb66da1..634599de 100644
--- a/src/placeBar.js
+++ b/src/placeBar.js
@@ -19,44 +19,29 @@
  * Author: James Westman <james flyingpimonster net>
  */
 
-const Clutter = imports.gi.Clutter;
-const Gdk = imports.gi.Gdk;
-const Geocode = imports.gi.GeocodeGlib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-
-const Application = imports.application;
-const ContactPlace = imports.contactPlace;
-const PlaceButtons = imports.placeButtons;
-const PlaceDialog = imports.placeDialog;
-const PlaceFormatter = imports.placeFormatter;
-const PlaceView = imports.placeView;
-const Utils = imports.utils;
-
-var PlaceBar = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/place-bar.ui',
-    InternalChildren: [ 'actionbar',
-                        'altSendToButton',
-                        'box',
-                        'eventbox',
-                        'contactAvatar',
-                        'title' ],
-    Properties: {
-        'place': GObject.ParamSpec.object('place',
-                                          'Place',
-                                          'The place to show information about',
-                                          GObject.ParamFlags.READABLE |
-                                          GObject.ParamFlags.WRITABLE,
-                                          Geocode.Place)
-    },
-}, class PlaceBar extends Gtk.Revealer {
-    _init(params) {
-        this._mapView = params.mapView;
+import Clutter from 'gi://Clutter';
+import Gdk from 'gi://Gdk';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+
+import {Application} from './application.js';
+import {ContactPlace} from './contactPlace.js';
+import {PlaceButtons} from './placeButtons.js';
+import {PlaceDialog} from './placeDialog.js';
+import {PlaceFormatter} from './placeFormatter.js';
+import {PlaceView} from './placeView.js';
+import * as Utils from './utils.js';
+
+export class PlaceBar extends Gtk.Revealer {
+    constructor(params) {
+        let mapView = params.mapView;
         delete params.mapView;
 
-        super._init(params);
+        super(params);
 
-        this._buttons = new PlaceButtons.PlaceButtons({ mapView: this._mapView });
+        this._mapView = mapView;
+        this._buttons = new PlaceButtons({ mapView: this._mapView });
         this._buttons.initSendToButton(this._altSendToButton);
         this._buttons.connect('place-edited', this._onPlaceEdited.bind(this));
         this._box.add(this._buttons);
@@ -82,10 +67,10 @@ var PlaceBar = GObject.registerClass({
             return;
         }
 
-        let formatter = new PlaceFormatter.PlaceFormatter(this.place);
+        let formatter = new PlaceFormatter(this.place);
         this._title.label = formatter.title;
 
-        if (this.place instanceof ContactPlace.ContactPlace) {
+        if (this.place instanceof ContactPlace) {
             this._contactAvatar.visible = true;
             this._contactAvatar.text = formatter.title;
 
@@ -117,17 +102,17 @@ var PlaceBar = GObject.registerClass({
                 this._box.remove(this._currentLocationView);
                 delete this._currentLocationView;
             } else {
-                this._currentLocationView = new PlaceView.PlaceView({ place: this.place,
-                                                                      mapView: this._mapView,
-                                                                      inlineMode: true,
-                                                                      visible: true });
+                this._currentLocationView = new PlaceView({ place: this.place,
+                                                            mapView: this._mapView,
+                                                            inlineMode: true,
+                                                            visible: true });
                 this._box.add(this._currentLocationView);
             }
         } else {
-            this._dialog = new PlaceDialog.PlaceDialog ({ transient_for: this.get_toplevel(),
-                                                        modal: true,
-                                                        mapView: this._mapView,
-                                                        place: this.place });
+            this._dialog = new PlaceDialog ({ transient_for: this.get_toplevel(),
+                                              modal: true,
+                                              mapView: this._mapView,
+                                              place: this.place });
             this._dialog.connect('response', () => {
                 this._dialog.destroy();
                 delete this._dialog;
@@ -157,4 +142,22 @@ var PlaceBar = GObject.registerClass({
 
         return Clutter.EVENT_PROPAGATE;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/place-bar.ui',
+    InternalChildren: [ 'actionbar',
+                        'altSendToButton',
+                        'box',
+                        'eventbox',
+                        'contactAvatar',
+                        'title' ],
+    Properties: {
+        'place': GObject.ParamSpec.object('place',
+                                          'Place',
+                                          'The place to show information about',
+                                          GObject.ParamFlags.READABLE |
+                                          GObject.ParamFlags.WRITABLE,
+                                          GeocodeGlib.Place)
+    },
+}, PlaceBar);
diff --git a/src/placeButtons.js b/src/placeButtons.js
index acbeeb2a..ad3e597f 100644
--- a/src/placeButtons.js
+++ b/src/placeButtons.js
@@ -20,39 +20,28 @@
  */
 
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-
-const Application = imports.application;
-const ContactPlace = imports.contactPlace;
-const OSMAccountDialog = imports.osmAccountDialog;
-const OSMEditDialog = imports.osmEditDialog;
-const OSMUtils = imports.osmUtils;
-const PlaceStore = imports.placeStore;
-const SendToDialog = imports.sendToDialog;
-
-var PlaceButtons = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/place-buttons.ui',
-    InternalChildren: [ 'routeButton',
-                        'sendToButton',
-                        'favoriteButton',
-                        'editButton',
-                        'favoriteButtonImage' ],
-    Signals: {
-        /* Emitted when the Edit dialog is closed, because the place details
-           might have changed and the parent PlaceBar/PlaceView needs
-           refreshing */
-        'place-edited': {}
-    }
-}, class PlaceButtons extends Gtk.Box {
-    _init(params) {
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+
+import {Application} from './application.js';
+import {ContactPlace} from './contactPlace.js';
+import {OSMAccountDialog} from './osmAccountDialog.js';
+import {OSMEditDialog} from './osmEditDialog.js';
+import * as OSMUtils from './osmUtils.js';
+import {PlaceStore} from './placeStore.js';
+import {SendToDialog} from './sendToDialog.js';
+
+export class PlaceButtons extends Gtk.Box {
+    constructor(params) {
         let place = params.place;
         delete params.place;
 
-        this._mapView = params.mapView;
+        let mapView = params.mapView;
         delete params.mapView;
 
-        super._init(params);
+        super(params);
+
+        this._mapView = mapView;
 
         this._initSignals();
 
@@ -76,7 +65,7 @@ var PlaceButtons = GObject.registerClass({
 
         this._updateFavoriteButton(!!this._place.store);
 
-        this._editButton.visible = (!(this._place instanceof ContactPlace.ContactPlace) &&
+        this._editButton.visible = (!(this._place instanceof ContactPlace) &&
                                     this._place.osm_id);
 
         this._routeButton.visible = !this._place.isCurrentLocation;
@@ -84,10 +73,10 @@ var PlaceButtons = GObject.registerClass({
 
     initSendToButton(button) {
         button.connect('clicked', () => {
-            let dialog = new SendToDialog.SendToDialog({ transient_for: this.get_toplevel(),
-                                                         modal: true,
-                                                         mapView: this._mapView,
-                                                         place: this._place });
+            let dialog = new SendToDialog({ transient_for: this.get_toplevel(),
+                                            modal: true,
+                                            mapView: this._mapView,
+                                            place: this._place });
             dialog.connect('response', () => dialog.destroy());
             dialog.show();
         });
@@ -184,4 +173,19 @@ var PlaceButtons = GObject.registerClass({
             }
         });
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/place-buttons.ui',
+    InternalChildren: [ 'routeButton',
+                        'sendToButton',
+                        'favoriteButton',
+                        'editButton',
+                        'favoriteButtonImage' ],
+    Signals: {
+        /* Emitted when the Edit dialog is closed, because the place details
+           might have changed and the parent PlaceBar/PlaceView needs
+           refreshing */
+        'place-edited': {}
+    }
+}, PlaceButtons);
diff --git a/src/placeDialog.js b/src/placeDialog.js
index 81cf6677..ce641f92 100644
--- a/src/placeDialog.js
+++ b/src/placeDialog.js
@@ -19,17 +19,14 @@
  * Author: James Westman <james flyingpimonster net>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const PlaceFormatter = imports.placeFormatter;
-const PlaceView = imports.placeView;
+import {PlaceFormatter} from './placeFormatter.js';
+import {PlaceView} from './placeView.js';
 
-var PlaceDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/place-dialog.ui',
-    InternalChildren: [ 'scroll' ]
-}, class PlaceDialog extends Gtk.Dialog {
-    _init(params) {
+export class PlaceDialog extends Gtk.Dialog {
+    constructor(params) {
         let place = params.place;
         delete params.place;
 
@@ -37,7 +34,7 @@ var PlaceDialog = GObject.registerClass({
         delete params.mapView;
 
         params.use_header_bar = true;
-        super._init(params);
+        super(params);
 
         if (this.transient_for.is_maximized) {
             this.maximize();
@@ -53,13 +50,18 @@ var PlaceDialog = GObject.registerClass({
             this.set_default_size(width, height);
         }
 
-        this._placeView = new PlaceView.PlaceView({ place,
-                                                    mapView,
-                                                    valign: Gtk.Align.START,
-                                                    visible: true });
+        this._placeView = new PlaceView({ place,
+                                          mapView,
+                                          valign: Gtk.Align.START,
+                                          visible: true });
         this._scroll.add(this._placeView);
 
-        let formatter = new PlaceFormatter.PlaceFormatter(place);
+        let formatter = new PlaceFormatter(place);
         this.title = formatter.title;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/place-dialog.ui',
+    InternalChildren: [ 'scroll' ]
+}, PlaceDialog);
diff --git a/src/placeEntry.js b/src/placeEntry.js
index 5167fd3f..f08bf468 100644
--- a/src/placeEntry.js
+++ b/src/placeEntry.js
@@ -20,22 +20,24 @@
  *         Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const _ = imports.gettext.gettext;
-
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const Gtk = imports.gi.Gtk;
-
-const Application = imports.application;
-const GeocodeFactory = imports.geocode;
-const Location = imports.location;
-const Place = imports.place;
-const PlaceStore = imports.placeStore;
-const PlacePopover = imports.placePopover;
-const URIS = imports.uris;
-const Utils = imports.utils;
+import gettext from 'gettext';
+
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import Gtk from 'gi://Gtk';
+
+import {Application} from './application.js';
+import * as GeocodeFactory from './geocode.js';
+import {Location} from './location.js';
+import {Place} from './place.js';
+import {PlaceStore} from './placeStore.js';
+import {PlacePopover} from './placePopover.js';
+import * as URIS from './uris.js';
+import * as Utils from './utils.js';
+
+const _ = gettext.gettext;
 
 // minimum number of characters to start completion
 const MIN_CHARS_COMPLETION = 3;
@@ -43,16 +45,7 @@ const MIN_CHARS_COMPLETION = 3;
 // pattern matching CJK ideographic characters
 const IDEOGRAPH_PATTERN = /[\u3300-\u9fff]/
 
-var PlaceEntry = GObject.registerClass({
-    Properties: {
-        'place': GObject.ParamSpec.object('place',
-                                          'Place',
-                                          'The selected place',
-                                          GObject.ParamFlags.READABLE |
-                                          GObject.ParamFlags.WRITABLE,
-                                          Geocode.Place)
-    }
-}, class PlaceEntry extends Gtk.SearchEntry {
+export class PlaceEntry extends Gtk.SearchEntry {
 
     set place(p) {
         if (!this._place && !p)
@@ -89,10 +82,10 @@ var PlaceEntry = GObject.registerClass({
         return this._popover;
     }
 
-    _init(props) {
-        let numVisible = props.num_visible || 6;
+    constructor(props) {
+        let numVisible = props.num_visible ?? 6;
         delete props.num_visible;
-        this._mapView = props.mapView;
+        let mapView = props.mapView;
         delete props.mapView;
 
         if (!props.loupe)
@@ -102,11 +95,13 @@ var PlaceEntry = GObject.registerClass({
         let maxChars = props.maxChars;
         delete props.maxChars;
 
-        this._matchRoute = props.matchRoute || false;
+        let matchRoute = props.matchRoute ?? false;
         delete props.matchRoute;
 
-        super._init(props);
+        super(props);
 
+        this._mapView = mapView;
+        this._matchRoute = matchRoute;
         this._filter = new Gtk.TreeModelFilter({ child_model: Application.placeStore });
         this._filter.set_visible_func(this._completionVisibleFunc.bind(this));
 
@@ -168,9 +163,9 @@ var PlaceEntry = GObject.registerClass({
     }
 
     _createPopover(numVisible, maxChars) {
-        let popover = new PlacePopover.PlacePopover({ num_visible:   numVisible,
-                                                      relative_to:   this,
-                                                      maxChars:      maxChars});
+        let popover = new PlacePopover({ num_visible:   numVisible,
+                                         relative_to:   this,
+                                         maxChars:      maxChars });
 
         this.connect('size-allocate', (widget, allocation) => {
             // Magic number to make the alignment pixel perfect.
@@ -215,11 +210,11 @@ var PlaceEntry = GObject.registerClass({
         let parsed = false;
 
         if (this.text.startsWith('geo:')) {
-            let location = new Geocode.Location();
+            let location = new GeocodeGlib.Location();
 
             try {
                 location.set_from_uri(this.text);
-                this.place = new Place.Place({ location: location });
+                this.place = new Place({ location: location });
             } catch(e) {
                 let msg = _("Failed to parse Geo URI");
                 Utils.showDialog(msg, Gtk.MessageType.ERROR, this.get_toplevel());
@@ -241,7 +236,7 @@ var PlaceEntry = GObject.registerClass({
             parsed = true;
         }
 
-        let parsedLocation = Place.Place.parseCoordinates(this.text);
+        let parsedLocation = Place.parseCoordinates(this.text);
         if (parsedLocation) {
             /* if the place was a parsed OSM coordinate URL, it will have
              * gotten re-written as bare coordinates and trigger a search-changed,
@@ -250,7 +245,7 @@ var PlaceEntry = GObject.registerClass({
              */
             if (!this.place ||
                 !this._roundedLocEquals(parsedLocation, this.place.location))
-                this.place = new Place.Place({ location: parsedLocation });
+                this.place = new Place({ location: parsedLocation });
             parsed = true;
         }
 
@@ -361,4 +356,15 @@ var PlaceEntry = GObject.registerClass({
         this._popover.updateResult(completedPlaces, searchText);
         this._popover.showResult();
     }
-});
+}
+
+GObject.registerClass({
+    Properties: {
+        'place': GObject.ParamSpec.object('place',
+                                          'Place',
+                                          'The selected place',
+                                          GObject.ParamFlags.READABLE |
+                                          GObject.ParamFlags.WRITABLE,
+                                          GeocodeGlib.Place)
+    }
+}, PlaceEntry);
diff --git a/src/placeFormatter.js b/src/placeFormatter.js
index 58dff6d1..d215c102 100644
--- a/src/placeFormatter.js
+++ b/src/placeFormatter.js
@@ -19,11 +19,11 @@
  * Author: Damián Nohales <damiannohales gmail com>
  */
 
-const Geocode = imports.gi.GeocodeGlib;
+import GeocodeGlib from 'gi://GeocodeGlib';
 
-const StoredRoute = imports.storedRoute;
+import {StoredRoute} from './storedRoute.js';
 
-var PlaceFormatter = class PlaceFormatter {
+export class PlaceFormatter {
 
     constructor(place) {
         this._place = place;
@@ -55,7 +55,7 @@ var PlaceFormatter = class PlaceFormatter {
     }
 
     getDetailsString() {
-        if (this._place instanceof StoredRoute.StoredRoute)
+        if (this._place instanceof StoredRoute)
             return this._place.viaString;
 
         return this.rows.map((row) => {
@@ -67,24 +67,24 @@ var PlaceFormatter = class PlaceFormatter {
 
     _update() {
         switch (this._place.place_type) {
-        case Geocode.PlaceType.COUNTRY:
+        case GeocodeGlib.PlaceType.COUNTRY:
             if (this._place.country)
                 this._titleProperty = 'country';
 
             this._addRow(['country_code']);
             break;
 
-        case Geocode.PlaceType.STATE:
+        case GeocodeGlib.PlaceType.STATE:
             if (this._place.state)
                 this._titleProperty = 'state';
             break;
 
-        case Geocode.PlaceType.COUNTY:
+        case GeocodeGlib.PlaceType.COUNTY:
             if (this._place.county)
                 this._titleProperty = 'county';
             break;
 
-        case Geocode.PlaceType.TOWN:
+        case GeocodeGlib.PlaceType.TOWN:
             if (this._place.county)
                 this._addRow(['county']);
             else if (this._place.state)
diff --git a/src/placeIcons.js b/src/placeIcons.js
index 66c449f0..9175f298 100644
--- a/src/placeIcons.js
+++ b/src/placeIcons.js
@@ -146,7 +146,7 @@ const TYPE_ICON_MAP = {
 /**
  * Get place icon name suitable for a Place.
  */
-function getIconForPlace(place) {
+export function getIconForPlace(place) {
     return TYPE_ICON_MAP?.[place.osmKey]?.[place.osmValue] ??
            TYPE_ICON_MAP?.[place.osmKey]?.['_'] ?? 'map-marker-symbolic';
 }
diff --git a/src/placeListRow.js b/src/placeListRow.js
index abb40b7d..2cd42659 100644
--- a/src/placeListRow.js
+++ b/src/placeListRow.js
@@ -17,28 +17,20 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const ContactPlace = imports.contactPlace;
-const PlaceFormatter = imports.placeFormatter;
-const PlaceStore = imports.placeStore;
-const Utils = imports.utils;
+import {ContactPlace} from './contactPlace.js';
+import {PlaceFormatter} from './placeFormatter.js';
+import {PlaceStore} from './placeStore.js';
+import * as Utils from './utils.js';
 
 var ROW_HEIGHT = 55;
 
-var PlaceListRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/place-list-row.ui',
-    InternalChildren: [ 'icon',
-                        'iconStack',
-                        'contactAvatar',
-                        'name',
-                        'details',
-                        'typeIcon' ],
-}, class PlaceListRow extends Gtk.ListBoxRow {
+export class PlaceListRow extends Gtk.ListBoxRow {
 
-    _init(params) {
+    constructor(params) {
         let place = params.place;
         delete params.place;
 
@@ -49,20 +41,20 @@ var PlaceListRow = GObject.registerClass({
         delete params.type;
 
         params.height_request = ROW_HEIGHT;
-        super._init(params);
+        super(params);
         this.update(place, type, searchString);
     }
 
     update(place, type, searchString) {
         this.place = place;
-        let formatter = new PlaceFormatter.PlaceFormatter(this.place);
+        let formatter = new PlaceFormatter(this.place);
         this.title = formatter.title;
         let markup = GLib.markup_escape_text(formatter.title, -1);
 
         this._name.label = this._boldMatch(markup, searchString);
         this._details.label = GLib.markup_escape_text(formatter.getDetailsString(),-1);
 
-        if (place instanceof ContactPlace.ContactPlace) {
+        if (place instanceof ContactPlace) {
             this._iconStack.set_visible_child(this._contactAvatar);
 
             this._contactAvatar.text = formatter.title;
@@ -102,4 +94,14 @@ var PlaceListRow = GObject.registerClass({
         }
         return title;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/place-list-row.ui',
+    InternalChildren: [ 'icon',
+                        'iconStack',
+                        'contactAvatar',
+                        'name',
+                        'details',
+                        'typeIcon' ],
+}, PlaceListRow);
diff --git a/src/placeMarker.js b/src/placeMarker.js
index 3aba8c8b..25a0fe9e 100644
--- a/src/placeMarker.js
+++ b/src/placeMarker.js
@@ -19,15 +19,14 @@
  * Author: Damián Nohales <damiannohales gmail com>
  */
 
-const GObject = imports.gi.GObject;
+import GObject from 'gi://GObject';
 
-const MapMarker = imports.mapMarker;
+import {MapMarker} from './mapMarker.js';
 
-var PlaceMarker = GObject.registerClass(
-class PlaceMarker extends MapMarker.MapMarker {
+export class PlaceMarker extends MapMarker {
 
-    _init(params) {
-        super._init(params);
+    constructor(params) {
+        super(params);
 
         this.add_actor(this._actorFromIconName('mark-location', 32));
     }
@@ -40,4 +39,6 @@ class PlaceMarker extends MapMarker.MapMarker {
     _hasBubble() {
         return true;
     }
-});
+}
+
+GObject.registerClass(PlaceMarker);
diff --git a/src/placePopover.js b/src/placePopover.js
index 4a0f0d63..c2af1c33 100644
--- a/src/placePopover.js
+++ b/src/placePopover.js
@@ -17,39 +17,29 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Application = imports.application;
-const PlaceListRow = imports.placeListRow;
-const PlaceStore = imports.placeStore;
-const SearchPopover = imports.searchPopover;
+import {Application} from './application.js';
+import {PlaceListRow} from './placeListRow.js';
+import {PlaceStore} from './placeStore.js';
+import {SearchPopover} from './searchPopover.js';
 
 const _PLACE_ICON_SIZE = 20;
 
-var PlacePopover = GObject.registerClass({
-    Signals : {
-        'selected' : { param_types: [ GObject.TYPE_OBJECT ] }
-    },
-    Template: 'resource:///org/gnome/Maps/ui/place-popover.ui',
-    InternalChildren: [ 'scrolledWindow',
-                        'stack',
-                        'spinner',
-                        'list',
-                        'noResultsLabel',
-                        'errorLabel' ],
-}, class PlacePopover extends SearchPopover.SearchPopover {
+export class PlacePopover extends SearchPopover {
 
-    _init(props) {
+    constructor(props) {
         let numVisible = props.num_visible;
         delete props.num_visible;
 
-        this._maxChars = props.maxChars;
+        let maxChars = props.maxChars;
         delete props.maxChars;
 
         props.transitions_enabled = false;
-        super._init(props);
+        super(props);
 
+        this._maxChars = maxChars;
         this._entry = this.relative_to;
 
         this._list.connect('row-activated', (list, row) => {
@@ -134,10 +124,23 @@ var PlacePopover = GObject.registerClass({
     }
 
     _addRow(place, type, searchString) {
-        let row = new PlaceListRow.PlaceListRow({ place: place,
-                                                  searchString: searchString,
-                                                  type: type,
-                                                  can_focus: true });
+        let row = new PlaceListRow({ place:        place,
+                                     searchString: searchString,
+                                     type:         type,
+                                     can_focus:    true });
         this._list.insert(row, -1);
     }
-});
+}
+
+GObject.registerClass({
+    Signals : {
+        'selected' : { param_types: [ GObject.TYPE_OBJECT ] }
+    },
+    Template: 'resource:///org/gnome/Maps/ui/place-popover.ui',
+    InternalChildren: [ 'scrolledWindow',
+                        'stack',
+                        'spinner',
+                        'list',
+                        'noResultsLabel',
+                        'errorLabel' ],
+}, PlacePopover);
diff --git a/src/placeStore.js b/src/placeStore.js
index 8dd8ed4a..e96c2cbf 100644
--- a/src/placeStore.js
+++ b/src/placeStore.js
@@ -17,49 +17,52 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const GdkPixbuf = imports.gi.GdkPixbuf;
-const Geocode = imports.gi.GeocodeGlib;
-const Gtk = imports.gi.Gtk;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import GdkPixbuf from 'gi://GdkPixbuf';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gtk from 'gi://Gtk';
 
-const ContactPlace = imports.contactPlace;
-const Place = imports.place;
-const StoredRoute = imports.storedRoute;
-const Utils = imports.utils;
+import {ContactPlace} from './contactPlace.js';
+import {Place} from './place.js';
+import {StoredRoute} from './storedRoute.js';
+import * as Utils from './utils.js';
 
 const _PLACES_STORE_FILE = 'maps-places.json';
 const _ICON_SIZE = 20;
 const _ONE_DAY = 1000 * 60 * 60 * 24; // one day in ms
 const _STALE_THRESHOLD = 7; // mark the osm information as stale after a week
 
-var PlaceType = {
-    ANY: -1,
-    RECENT: 0,
-    FAVORITE: 1,
-    CONTACT: 2,
-    RECENT_ROUTE: 3
-};
-
-var Columns = {
-    PLACE_ICON: 0,
-    PLACE: 1,
-    NAME: 2,
-    TYPE: 3,
-    ADDED: 4,
-    LANGUAGE: 5
-};
-
-var PlaceStore = GObject.registerClass(
-class PlaceStore extends Gtk.ListStore {
-
-    _init(params) {
-        this._recentPlacesLimit = params.recentPlacesLimit;
+export class PlaceStore extends Gtk.ListStore {
+
+    static PlaceType = {
+        ANY: -1,
+        RECENT: 0,
+        FAVORITE: 1,
+        CONTACT: 2,
+        RECENT_ROUTE: 3
+    }
+
+    static Columns = {
+        PLACE_ICON: 0,
+        PLACE: 1,
+        NAME: 2,
+        TYPE: 3,
+        ADDED: 4,
+        LANGUAGE: 5
+    }
+
+    constructor(params) {
+        let recentPlacesLimit = params.recentPlacesLimit;
         delete params.recentPlacesLimit;
 
-        this._recentRoutesLimit = params.recentRoutesLimit;
+        let recentRoutesLimit = params.recentRoutesLimit;
         delete params.recentRoutesLimit;
 
+        super(params);
+
+        this._recentPlacesLimit = recentPlacesLimit;
+        this._recentRoutesLimit = recentRoutesLimit;
         this._numRecentPlaces = 0;
         this._numRecentRoutes = 0;
         this.filename = GLib.build_filenamev([GLib.get_user_data_dir(),
@@ -67,7 +70,6 @@ class PlaceStore extends Gtk.ListStore {
         this._typeTable = {};
         this._language = Utils.getLanguage();
 
-        super._init(params);
         this.set_column_types([GdkPixbuf.Pixbuf,
                                GObject.TYPE_OBJECT,
                                GObject.TYPE_STRING,
@@ -75,7 +77,7 @@ class PlaceStore extends Gtk.ListStore {
                                GObject.TYPE_DOUBLE,
                                GObject.TYPE_STRING]);
 
-        this.set_sort_column_id(Columns.ADDED, Gtk.SortType.ASCENDING);
+        this.set_sort_column_id(PlaceStore.Columns.ADDED, Gtk.SortType.ASCENDING);
     }
 
     _addPlace(place, type) {
@@ -85,35 +87,35 @@ class PlaceStore extends Gtk.ListStore {
     }
 
     _addContact(place) {
-        if (this.exists(place, PlaceType.CONTACT)) {
+        if (this.exists(place, PlaceStore.PlaceType.CONTACT)) {
             return;
         }
 
-        this._addPlace(place, PlaceType.CONTACT);
+        this._addPlace(place, PlaceStore.PlaceType.CONTACT);
     }
 
     _addFavorite(place) {
         if (!place.store)
             return;
 
-        if (this.exists(place, PlaceType.FAVORITE)) {
+        if (this.exists(place, PlaceStore.PlaceType.FAVORITE)) {
             return;
         }
 
-        if (this.exists(place, PlaceType.RECENT)) {
+        if (this.exists(place, PlaceStore.PlaceType.RECENT)) {
             this._removeIf((model, iter) => {
-                let p = model.get_value(iter, Columns.PLACE);
+                let p = model.get_value(iter, PlaceStore.Columns.PLACE);
                 return p.uniqueID === place.uniqueID;
             }, true);
         }
-        this._addPlace(place, PlaceType.FAVORITE);
+        this._addPlace(place, PlaceStore.PlaceType.FAVORITE);
     }
 
     _addRecent(place) {
         if (!place.store)
             return;
 
-        if (this.exists(place, PlaceType.RECENT)) {
+        if (this.exists(place, PlaceStore.PlaceType.RECENT)) {
             this.updatePlace(place);
             return;
         }
@@ -122,10 +124,10 @@ class PlaceStore extends Gtk.ListStore {
             // Since we sort by added, the oldest recent will be
             // the first one we encounter.
             this._removeIf((model, iter) => {
-                let type = model.get_value(iter, Columns.TYPE);
+                let type = model.get_value(iter, PlaceStore.Columns.TYPE);
 
-                if (type === PlaceType.RECENT) {
-                    let place = model.get_value(iter, Columns.PLACE);
+                if (type === PlaceStore.PlaceType.RECENT) {
+                    let place = model.get_value(iter, PlaceStore.Columns.PLACE);
                     this._typeTable[place.uniqueID] = null;
                     this._numRecentPlaces--;
                     return true;
@@ -133,12 +135,12 @@ class PlaceStore extends Gtk.ListStore {
                 return false;
             }, true);
         }
-        this._addPlace(place, PlaceType.RECENT);
+        this._addPlace(place, PlaceStore.PlaceType.RECENT);
         this._numRecentPlaces++;
     }
 
     _addRecentRoute(stored) {
-        if (this.exists(stored, PlaceType.RECENT_ROUTE))
+        if (this.exists(stored, PlaceStore.PlaceType.RECENT_ROUTE))
             return;
 
         if (stored.containsCurrentLocation)
@@ -146,10 +148,10 @@ class PlaceStore extends Gtk.ListStore {
 
         if (this._numRecentRoutes >= this._recentRoutesLimit) {
             this._removeIf((model, iter) => {
-                let type = model.get_value(iter, Columns.TYPE);
+                let type = model.get_value(iter, PlaceStore.Columns.TYPE);
 
-                if (type === PlaceType.RECENT_ROUTE) {
-                    let place = model.get_value(iter, Columns.PLACE);
+                if (type === PlaceStore.PlaceType.RECENT_ROUTE) {
+                    let place = model.get_value(iter, PlaceStore.Columns.PLACE);
                     this._typeTable[place.uniqueID] = null;
                     this._numRecentRoutes--;
                     return true;
@@ -157,7 +159,7 @@ class PlaceStore extends Gtk.ListStore {
                 return false;
             }, true);
         }
-        this._addPlace(stored, PlaceType.RECENT_ROUTE);
+        this._addPlace(stored, PlaceStore.PlaceType.RECENT_ROUTE);
         this._numRecentRoutes++;
     }
 
@@ -182,31 +184,32 @@ class PlaceStore extends Gtk.ListStore {
                     language = '';
 
                 let p;
-                if (type === PlaceType.RECENT_ROUTE) {
+                if (type === PlaceStore.PlaceType.RECENT_ROUTE) {
                     if (this._numRecentRoutes >= this._recentRoutesLimit)
                         return;
-                    p = StoredRoute.StoredRoute.fromJSON(place);
+                    p = StoredRoute.fromJSON(place);
                     this._numRecentRoutes++;
                 } else {
-                    p = Place.Place.fromJSON(place);
-                    if (type === PlaceType.RECENT)
+                    p = Place.fromJSON(place);
+                    if (type === PlaceStore.PlaceType.RECENT)
                         this._numRecentPlaces++;
                 }
                 this._setPlace(this.append(), p, type, added, language);
             });
         } catch (e) {
+            log('stack: ' + e.stack);
             throw new Error('failed to parse places file');
         }
     }
 
     addPlace(place, type) {
-        if (type === PlaceType.FAVORITE)
+        if (type === PlaceStore.PlaceType.FAVORITE)
             this._addFavorite(place, type);
-        else if (type === PlaceType.RECENT)
+        else if (type === PlaceStore.PlaceType.RECENT)
             this._addRecent(place, type);
-        else if (type === PlaceType.CONTACT)
+        else if (type === PlaceStore.PlaceType.CONTACT)
             this._addContact(place, type);
-        else if (type === PlaceType.RECENT_ROUTE)
+        else if (type === PlaceStore.PlaceType.RECENT_ROUTE)
             this._addRecentRoute(place);
     }
 
@@ -215,7 +218,7 @@ class PlaceStore extends Gtk.ListStore {
             return;
 
         this._removeIf((model, iter) => {
-            let p = model.get_value(iter, Columns.PLACE);
+            let p = model.get_value(iter, PlaceStore.Columns.PLACE);
             if (p.uniqueID === place.uniqueID) {
                 this._typeTable[place.uniqueID] = null;
                 return true;
@@ -229,7 +232,7 @@ class PlaceStore extends Gtk.ListStore {
         let filter = new Gtk.TreeModelFilter({ child_model: this });
 
         filter.set_visible_func((model, iter) => {
-            let type = model.get_value(iter, Columns.TYPE);
+            let type = model.get_value(iter, PlaceStore.Columns.TYPE);
             return (type === placeType);
         });
 
@@ -239,10 +242,10 @@ class PlaceStore extends Gtk.ListStore {
     _store() {
         let jsonArray = [];
         this.foreach((model, path, iter) => {
-            let place = model.get_value(iter, Columns.PLACE);
-            let type = model.get_value(iter, Columns.TYPE);
-            let added = model.get_value(iter, Columns.ADDED);
-            let language = model.get_value(iter, Columns.LANGUAGE);
+            let place = model.get_value(iter, PlaceStore.Columns.PLACE);
+            let type = model.get_value(iter, PlaceStore.Columns.TYPE);
+            let added = model.get_value(iter, PlaceStore.Columns.ADDED);
+            let language = model.get_value(iter, PlaceStore.Columns.LANGUAGE);
 
             if (!place || !place.store)
                 return;
@@ -261,11 +264,11 @@ class PlaceStore extends Gtk.ListStore {
 
     _setPlace(iter, place, type, added, language) {
         this.set(iter,
-                 [Columns.PLACE,
-                  Columns.NAME,
-                  Columns.TYPE,
-                  Columns.ADDED,
-                  Columns.LANGUAGE],
+                 [PlaceStore.Columns.PLACE,
+                  PlaceStore.Columns.NAME,
+                  PlaceStore.Columns.TYPE,
+                  PlaceStore.Columns.ADDED,
+                  PlaceStore.Columns.LANGUAGE],
                  [place,
                   place.name,
                   type,
@@ -274,7 +277,7 @@ class PlaceStore extends Gtk.ListStore {
 
         if (place.icon !== null) {
             Utils.load_icon(place.icon, _ICON_SIZE, (pixbuf) => {
-                this.set(iter, [Columns.ICON], [pixbuf]);
+                this.set(iter, [PlaceStore.Columns.ICON], [pixbuf]);
             });
         }
         this._typeTable[place.uniqueID] = type;
@@ -284,7 +287,7 @@ class PlaceStore extends Gtk.ListStore {
         let storedPlace = null;
 
         this.foreach((model, path, iter) => {
-            let p = model.get_value(iter, Columns.PLACE);
+            let p = model.get_value(iter, PlaceStore.Columns.PLACE);
             if (p.uniqueID === place.uniqueID) {
                 storedPlace = p;
                 return true;
@@ -301,12 +304,12 @@ class PlaceStore extends Gtk.ListStore {
         let added = null;
         let language = null;
         this.foreach((model, path, iter) => {
-            let p = model.get_value(iter, Columns.PLACE);
+            let p = model.get_value(iter, PlaceStore.Columns.PLACE);
 
             if (p.uniqueID === place.uniqueID) {
-                let p_type = model.get_value(iter, Columns.TYPE);
-                added = model.get_value(iter, Columns.ADDED);
-                language = model.get_value(iter, Columns.LANGUAGE);
+                let p_type = model.get_value(iter, PlaceStore.Columns.TYPE);
+                added = model.get_value(iter, PlaceStore.Columns.ADDED);
+                language = model.get_value(iter, PlaceStore.Columns.LANGUAGE);
             }
         });
 
@@ -345,10 +348,10 @@ class PlaceStore extends Gtk.ListStore {
 
     updatePlace(place) {
         this.foreach((model, path, iter) => {
-            let p = model.get_value(iter, Columns.PLACE);
+            let p = model.get_value(iter, PlaceStore.Columns.PLACE);
 
             if (p.uniqueID === place.uniqueID) {
-                let type = model.get_value(iter, Columns.TYPE);
+                let type = model.get_value(iter, PlaceStore.Columns.TYPE);
                 this._setPlace(iter, place, type, new Date().getTime(),
                                this._language);
                 this._store();
@@ -356,4 +359,6 @@ class PlaceStore extends Gtk.ListStore {
             }
         });
     }
-});
+}
+
+GObject.registerClass(PlaceStore);
diff --git a/src/placeView.js b/src/placeView.js
index 70fca550..d752a8bd 100644
--- a/src/placeView.js
+++ b/src/placeView.js
@@ -19,26 +19,26 @@
  * Author: Damián Nohales <damiannohales gmail com>
  */
 
-const Geocode = imports.gi.GeocodeGlib;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Pango = imports.gi.Pango;
+import GeocodeGlib from 'gi://GeocodeGlib';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Pango from 'gi://Pango';
 
 const Format = imports.format;
 
-const Application = imports.application;
-const ContactPlace = imports.contactPlace;
-const Overpass = imports.overpass;
-const Place = imports.place;
-const PlaceIcons = imports.placeIcons;
-const PlaceViewImage = imports.placeViewImage;
-const PlaceButtons = imports.placeButtons;
-const PlaceFormatter = imports.placeFormatter;
-const PlaceStore = imports.placeStore;
-const Translations = imports.translations;
-const Utils = imports.utils;
-const Wikipedia = imports.wikipedia;
+import {Application} from './application.js';
+import {ContactPlace} from './contactPlace.js';
+import {Overpass} from './overpass.js';
+import {Place} from './place.js';
+import * as PlaceIcons from './placeIcons.js';
+import {PlaceViewImage} from './placeViewImage.js';
+import {PlaceButtons} from './placeButtons.js';
+import {PlaceFormatter} from './placeFormatter.js';
+import {PlaceStore} from './placeStore.js';
+import * as Translations from './translations.js';
+import * as Utils from './utils.js';
+import * as Wikipedia from './wikipedia.js';
 
 // maximum dimension of thumbnails to fetch from Wikipedia
 const THUMBNAIL_FETCH_SIZE = 360;
@@ -46,19 +46,10 @@ const THUMBNAIL_FETCH_SIZE = 360;
 // Unicode left-to-right marker
 const LRM = '\u200E';
 
-var PlaceView = GObject.registerClass({
-    Properties: {
-        'overpass-place': GObject.ParamSpec.object('overpass-place',
-                                                   'Overpass Place',
-                                                   'The place as filled in by Overpass',
-                                                   GObject.ParamFlags.READABLE |
-                                                   GObject.ParamFlags.WRITABLE,
-                                                   Geocode.Place)
-    }
-}, class PlaceView extends Gtk.Box {
+export class PlaceView extends Gtk.Box {
 
-    _init(params) {
-        this._place = params.place;
+    constructor(params) {
+        let place = params.place;
         delete params.place;
 
         let mapView = params.mapView;
@@ -66,10 +57,13 @@ var PlaceView = GObject.registerClass({
 
         /* This mode is used in PlaceBar for inline current location details.
            It hides the title box and decreases the start margin on the rows. */
-        this._inlineMode = !!params.inlineMode;
+        let inlineMode = !!params.inlineMode;
         delete params.inlineMode;
 
-        super._init(params);
+        super(params);
+
+        this._place = place;
+        this._inlineMode = inlineMode;
 
         let ui = Utils.getUIObject('place-view', [ 'bubble-main-box',
                                                    'bubble-spinner',
@@ -97,8 +91,8 @@ var PlaceView = GObject.registerClass({
 
         this.add(this._mainStack);
 
-        let placeButtons = new PlaceButtons.PlaceButtons({ place: this._place,
-                                                           mapView: mapView });
+        let placeButtons = new PlaceButtons({ place: this._place,
+                                              mapView: mapView });
         placeButtons.connect('place-edited', this._onPlaceEdited.bind(this));
         ui.placeButtons.add(placeButtons);
 
@@ -120,7 +114,7 @@ var PlaceView = GObject.registerClass({
         }
 
         /* Set up contact avatar */
-        if (this.place instanceof ContactPlace.ContactPlace) {
+        if (this.place instanceof ContactPlace) {
             this._contactAvatar.visible = true;
             Utils.load_icon(this.place.icon, 32, (pixbuf) => {
                 this._contactAvatar.set_image_load_func((size) => Utils.loadAvatar(pixbuf, size));
@@ -137,7 +131,7 @@ var PlaceView = GObject.registerClass({
         if (this.place.isCurrentLocation) {
             this._populate(this.place);
         } else {
-            let overpass = new Overpass.Overpass();
+            let overpass = new Overpass();
 
             /* use a property binding from the Overpass instance to avoid
              * accessing this object after the underlying GObject has
@@ -201,7 +195,7 @@ var PlaceView = GObject.registerClass({
 
     updatePlaceDetails() {
         let place = this.place;
-        let formatter = new PlaceFormatter.PlaceFormatter(place);
+        let formatter = new PlaceFormatter(place);
 
         let address = formatter.rows.map((row) => {
             row = row.map(function(prop) {
@@ -660,4 +654,15 @@ var PlaceView = GObject.registerClass({
     _onPlaceEdited() {
         this._populate(this._place);
     }
-});
+}
+
+GObject.registerClass({
+    Properties: {
+        'overpass-place': GObject.ParamSpec.object('overpass-place',
+                                                   'Overpass Place',
+                                                   'The place as filled in by Overpass',
+                                                   GObject.ParamFlags.READABLE |
+                                                   GObject.ParamFlags.WRITABLE,
+                                                   GeocodeGlib.Place)
+    }
+}, PlaceView);
diff --git a/src/placeViewImage.js b/src/placeViewImage.js
index 56d0c2cb..44670d59 100644
--- a/src/placeViewImage.js
+++ b/src/placeViewImage.js
@@ -19,18 +19,17 @@
  * Author: James Westman <james flyingpimonster net>
  */
 
-const Cairo = imports.cairo;
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Cairo from 'cairo';
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
 /* The maximum aspect ratio, after which the image will be cropped vertically */
 const MAX_ASPECT_RATIO = 1;
 
-var PlaceViewImage = GObject.registerClass(
-class PlaceViewImage extends Gtk.DrawingArea {
-    _init(params) {
-        super._init(params);
+export class PlaceViewImage extends Gtk.DrawingArea {
+    constructor(params) {
+        super(params);
 
         this._pixbuf = null;
         this._cached = null;
@@ -98,4 +97,6 @@ class PlaceViewImage extends Gtk.DrawingArea {
             return [0, 0];
         }
     }
-});
+}
+
+GObject.registerClass(PlaceViewImage);
diff --git a/src/placeZoom.js b/src/placeZoom.js
index 0f797269..c895a17a 100644
--- a/src/placeZoom.js
+++ b/src/placeZoom.js
@@ -65,7 +65,7 @@ const TYPE_ZOOM_MAP = {
  * otherwise return undefined, in which case the maximum zoom level
  * (as defined by the map source) could be used.
  */
-function getZoomLevelForPlace(place) {
+export function getZoomLevelForPlace(place) {
     return TYPE_ZOOM_MAP?.[place.osmKey]?.[place.osmValue] ??
            TYPE_ZOOM_MAP?.[place.osmKey]?.['_'];
 }
diff --git a/src/printLayout.js b/src/printLayout.js
index e57fac57..858e174f 100644
--- a/src/printLayout.js
+++ b/src/printLayout.js
@@ -17,24 +17,21 @@
  * Author: Amisha Singla <amishas157 gmail com>
  */
 
-const Cairo = imports.cairo;
-const Champlain = imports.gi.Champlain;
-const Clutter = imports.gi.Clutter;
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Pango = imports.gi.Pango;
-const PangoCairo = imports.gi.PangoCairo;
-
-const Application = imports.application;
-const Color = imports.color;
-const MapView = imports.mapView;
-const MapSource = imports.mapSource;
-const TurnPointMarker = imports.turnPointMarker;
-const Utils = imports.utils;
-
-/* Following constant has unit as meters */
-const _SHORT_LAYOUT_MAX_DISTANCE = 3000;
+import Cairo from 'cairo';
+import Champlain from 'gi://Champlain';
+import Clutter from 'gi://Clutter';
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Pango from 'gi://Pango';
+import PangoCairo from 'gi://PangoCairo';
+
+import {Application} from './application.js';
+import * as Color from './color.js';
+import {MapView} from './mapView.js';
+import * as MapSource from './mapSource.js';
+import {TurnPointMarker} from './turnPointMarker.js';
+import * as Utils from './utils.js';
 
 const _STROKE_COLOR = new Clutter.Color({ red: 0,
                                           blue: 255,
@@ -55,45 +52,23 @@ const _MapView = {
     ZOOM_LEVEL: 18
 };
 
-function newFromRoute(route, pageWidth, pageHeight) {
-    /*
-     * To avoid the circular dependencies, imports has
-     * been carried out in this method
-     */
-    if (route.distance > _SHORT_LAYOUT_MAX_DISTANCE) {
-        return new imports.longPrintLayout.LongPrintLayout({
-            route: route,
-            pageWidth: pageWidth,
-            pageHeight: pageHeight
-        });
-    } else {
-        return new imports.shortPrintLayout.ShortPrintLayout({
-            route: route,
-            pageWidth: pageWidth,
-            pageHeight: pageHeight
-        });
-    }
-}
-
-var PrintLayout = GObject.registerClass({
-    Abstract: true,
-    Signals: {
-        'render-complete': { }
-    }
-}, class PrintLayout extends GObject.Object {
+export class PrintLayout extends GObject.Object {
 
-    _init(params) {
-        this._pageWidth = params.pageWidth;
+    constructor(params) {
+        let pageWidth = params.pageWidth;
         delete params.pageWidth;
 
-        this._pageHeight = params.pageHeight;
+        let pageHeight = params.pageHeight;
         delete params.pageHeight;
 
-        this._totalSurfaces = params.totalSurfaces;
+        let totalSurfaces = params.totalSurfaces;
         delete params.totalSurfaces;
 
-        super._init(params);
+        super(params);
 
+        this._pageWidth = pageWidth;
+        this._pageHeight = pageHeight;
+        this._totalSurfaces = totalSurfaces;
         this.numPages = 0;
         this.surfaceObjects = [];
         this._surfacesRendered = 0;
@@ -142,10 +117,7 @@ var PrintLayout = GObject.registerClass({
     }
 
     _createMarker(turnPoint) {
-        return new TurnPointMarker.TurnPointMarker({
-            turnPoint: turnPoint,
-            queryPoint: {}
-        });
+        return new TurnPointMarker({ turnPoint: turnPoint, queryPoint: {} });
     }
 
     _drawMapView(width, height, zoomLevel, turnPoints) {
@@ -370,4 +342,11 @@ var PrintLayout = GObject.registerClass({
 
         return name;
     }
-});
+}
+
+GObject.registerClass({
+    Abstract: true,
+    Signals: {
+        'render-complete': { }
+    }
+}, PrintLayout);
diff --git a/src/printOperation.js b/src/printOperation.js
index b3307c0a..33dcc9c3 100644
--- a/src/printOperation.js
+++ b/src/printOperation.js
@@ -17,17 +17,21 @@
  * Author: Amisha Singla <amishas157 gmail com>
  */
 
-const Gtk = imports.gi.Gtk;
+import Gtk from 'gi://Gtk';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const PrintLayout = imports.printLayout;
-const TransitPrintLayout = imports.transitPrintLayout;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import {LongPrintLayout} from './longPrintLayout.js';
+import {ShortPrintLayout} from './shortPrintLayout.js';
+import {TransitPrintLayout} from './transitPrintLayout.js';
+import * as Utils from './utils.js';
 
 const _MIN_TIME_TO_ABORT = 3000;
 
-var PrintOperation = class PrintOperation {
+/* Following constant has unit as meters */
+const _SHORT_LAYOUT_MAX_DISTANCE = 3000;
+
+export class PrintOperation {
 
     constructor(params) {
         this._mainWindow = params.mainWindow;
@@ -70,11 +74,19 @@ var PrintOperation = class PrintOperation {
 
         if (selectedTransitItinerary) {
             this._layout =
-                new TransitPrintLayout.TransitPrintLayout({ itinerary: selectedTransitItinerary,
-                                                            pageWidth: width,
-                                                            pageHeight: height });
+                new TransitPrintLayout({ itinerary: selectedTransitItinerary,
+                                         pageWidth: width,
+                                         pageHeight: height });
         } else {
-            this._layout = PrintLayout.newFromRoute(route, width, height);
+            if (route.distance > _SHORT_LAYOUT_MAX_DISTANCE) {
+                return new LongPrintLayout({ route: route,
+                                             pageWidth: pageWidth,
+                                             pageHeight: pageHeight });
+            } else {
+                return new ShortPrintLayout({ route: route,
+                                              pageWidth: pageWidth,
+                                              pageHeight: pageHeight });
+            }
         }
         this._layout.render();
     }
@@ -116,4 +128,4 @@ var PrintOperation = class PrintOperation {
             Utils.debug('Failed to print: %s'.format(e.message));
         }
     }
-};
+}
diff --git a/src/route.js b/src/route.js
index 0ef127fc..f370fedb 100644
--- a/src/route.js
+++ b/src/route.js
@@ -19,31 +19,10 @@
  * Author: Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const GObject = imports.gi.GObject;
-
-const BoundingBox = imports.boundingBox;
-const Utils = imports.utils;
-
-var TurnPointType = {
-    START:            0,
-    SHARP_LEFT:       1,
-    LEFT:             2,
-    SLIGHT_LEFT:      3,
-    KEEP_LEFT:        4,
-    CONTINUE:         5,
-    SLIGHT_RIGHT:     6,
-    RIGHT:            7,
-    SHARP_RIGHT:      8,
-    KEEP_RIGHT:       9,
-    END:              10,
-    VIA:              11,
-    ROUNDABOUT:       12,
-    LEAVE_ROUNDABOUT: 13,
-    UTURN:            14,
-    UTURN_LEFT:       15,
-    UTURN_RIGHT:      16,
-    ELEVATOR:         17
-};
+import GObject from 'gi://GObject';
+
+import {BoundingBox} from './boundingBox.js';
+import * as Utils from './utils.js';
 
 /* countries/terrotories driving on the left
  * source: https://en.wikipedia.org/wiki/Left-_and_right-hand_traffic
@@ -58,16 +37,10 @@ const LHT_COUNTRIES = new Set(['AG', 'AI', 'AU', 'BB', 'BD', 'BM', 'BN', 'BS',
                                'TO', 'TT', 'TV', 'TZ', 'UG', 'VC', 'VG', 'VI',
                                'WS', 'ZA', 'ZM', 'ZW']);
 
-var Route = GObject.registerClass({
-    Signals: {
-        'update': {},
-        'reset': {},
-        'error': { param_types: [GObject.TYPE_STRING] }
-    }
-}, class Route extends GObject.Object {
+export class Route extends GObject.Object {
 
-    _init() {
-        super._init();
+    constructor() {
+        super();
         this.reset();
     }
 
@@ -95,15 +68,44 @@ var Route = GObject.registerClass({
     }
 
     createBBox(coordinates) {
-        let bbox = new BoundingBox.BoundingBox();
+        let bbox = new BoundingBox();
         coordinates.forEach(function({ latitude, longitude }) {
             bbox.extend(latitude, longitude);
         }, this);
         return bbox;
     }
-});
+}
 
-var TurnPoint = class TurnPoint {
+GObject.registerClass({
+    Signals: {
+        'update': {},
+        'reset': {},
+        'error': { param_types: [GObject.TYPE_STRING] }
+    }
+}, Route);
+
+export class TurnPoint {
+
+    static Type = {
+        START:            0,
+        SHARP_LEFT:       1,
+        LEFT:             2,
+        SLIGHT_LEFT:      3,
+        KEEP_LEFT:        4,
+        CONTINUE:         5,
+        SLIGHT_RIGHT:     6,
+        RIGHT:            7,
+        SHARP_RIGHT:      8,
+        KEEP_RIGHT:       9,
+        END:              10,
+        VIA:              11,
+        ROUNDABOUT:       12,
+        LEAVE_ROUNDABOUT: 13,
+        UTURN:            14,
+        UTURN_LEFT:       15,
+        UTURN_RIGHT:      16,
+        ELEVATOR:         17
+    }
 
     constructor({ coordinate, type, distance, instruction, turnAngle }) {
         this.coordinate = coordinate;
@@ -118,30 +120,30 @@ var TurnPoint = class TurnPoint {
     }
 
     isStop() {
-        return this._type === TurnPointType.START
-            || this._type === TurnPointType.VIA
-            || this._type === TurnPointType.END;
+        return this._type === TurnPoint.Type.START
+            || this._type === TurnPoint.Type.VIA
+            || this._type === TurnPoint.Type.END;
     }
 
     _getIconName(turnAngle) {
         switch(this._type) {
-        case TurnPointType.SHARP_LEFT:   return 'maps-direction-sharpleft-symbolic';
-        case TurnPointType.LEFT:         return 'maps-direction-left-symbolic';
-        case TurnPointType.SLIGHT_LEFT:  return 'maps-direction-slightleft-symbolic';
-        case TurnPointType.CONTINUE:     return 'maps-direction-continue-symbolic';
-        case TurnPointType.SLIGHT_RIGHT: return 'maps-direction-slightright-symbolic';
-        case TurnPointType.RIGHT:        return 'maps-direction-right-symbolic';
-        case TurnPointType.SHARP_RIGHT:  return 'maps-direction-sharpright-symbolic';
-        case TurnPointType.START:        return 'maps-point-start-symbolic';
-        case TurnPointType.VIA:          return 'maps-point-end-symbolic';
-        case TurnPointType.END:          return 'maps-point-end-symbolic';
-        case TurnPointType.ROUNDABOUT:   return this._getRoundaboutIconName(turnAngle);
-        case TurnPointType.ELEVATOR:     return 'maps-direction-elevator-symbolic';
-        case TurnPointType.UTURN:        return this._isLefthandTraffic() ?
+        case TurnPoint.Type.SHARP_LEFT:   return 'maps-direction-sharpleft-symbolic';
+        case TurnPoint.Type.LEFT:         return 'maps-direction-left-symbolic';
+        case TurnPoint.Type.SLIGHT_LEFT:  return 'maps-direction-slightleft-symbolic';
+        case TurnPoint.Type.CONTINUE:     return 'maps-direction-continue-symbolic';
+        case TurnPoint.Type.SLIGHT_RIGHT: return 'maps-direction-slightright-symbolic';
+        case TurnPoint.Type.RIGHT:        return 'maps-direction-right-symbolic';
+        case TurnPoint.Type.SHARP_RIGHT:  return 'maps-direction-sharpright-symbolic';
+        case TurnPoint.Type.START:        return 'maps-point-start-symbolic';
+        case TurnPoint.Type.VIA:          return 'maps-point-end-symbolic';
+        case TurnPoint.Type.END:          return 'maps-point-end-symbolic';
+        case TurnPoint.Type.ROUNDABOUT:   return this._getRoundaboutIconName(turnAngle);
+        case TurnPoint.Type.ELEVATOR:     return 'maps-direction-elevator-symbolic';
+        case TurnPoint.Type.UTURN:        return this._isLefthandTraffic() ?
                                                 'maps-direction-u-turn-right-symbolic':
                                                 'maps-direction-u-turn-left-symbolic';
-        case TurnPointType.UTURN_LEFT:   return 'maps-direction-u-turn-left-symbolic';
-        case TurnPointType.UTURN_RIGHT:  return 'maps-direction-u-turn-right-symbolic';
+        case TurnPoint.Type.UTURN_LEFT:   return 'maps-direction-u-turn-left-symbolic';
+        case TurnPoint.Type.UTURN_RIGHT:  return 'maps-direction-u-turn-right-symbolic';
         default:                         return '';
         }
     }
@@ -181,4 +183,4 @@ var TurnPoint = class TurnPoint {
 
         return LHT_COUNTRIES.has(country);
     }
-};
+}
diff --git a/src/routeEntry.js b/src/routeEntry.js
index c2b62fc7..5d2018ed 100644
--- a/src/routeEntry.js
+++ b/src/routeEntry.js
@@ -17,43 +17,41 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Application = imports.application;
-const PlaceEntry = imports.placeEntry;
-const RouteQuery = imports.routeQuery;
+import {Application} from './application.js';
+import {PlaceEntry} from './placeEntry.js';
+import {RouteQuery} from './routeQuery.js';
 
-var Type = {
-    FROM: 0,
-    TO: 1,
-    VIA: 2
-};
+const _ = gettext.gettext;
 
-var RouteEntry = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/route-entry.ui',
-    Children: [ 'iconEventBox' ],
-    InternalChildren: [ 'entryGrid',
-                        'icon',
-                        'button',
-                        'buttonImage' ]
-}, class RouteEntry extends Gtk.Grid {
+export class RouteEntry extends Gtk.Grid {
+
+    static Type = {
+        FROM: 0,
+        TO: 1,
+        VIA: 2
+    }
 
-    _init(params) {
-        this._type = params.type;
+    constructor(params) {
+        let type = params.type;
         delete params.type;
 
-        this._point = params.point || null;
+        let point = params.point ?? null;
         delete params.point;
 
-        this._mapView = params.mapView || null;
+        let mapView = params.mapView ?? null;
         delete params.mapView;
 
-        super._init(params);
+        super(params);
 
+        this._type = type;
+        this._point = point;
+        this._mapView = mapView;
         this.entry = this._createEntry();
         this._entryGrid.attach(this.entry, 0, 0, 1, 1);
 
@@ -66,7 +64,7 @@ var RouteEntry = GObject.registerClass({
         });
 
         switch (this._type) {
-        case Type.FROM:
+        case RouteEntry.Type.FROM:
             let query = Application.routeQuery;
             this._buttonImage.icon_name = 'list-add-symbolic';
             this._icon.icon_name = 'maps-point-start-symbolic';
@@ -77,13 +75,13 @@ var RouteEntry = GObject.registerClass({
             });
 
             break;
-        case Type.VIA:
+        case RouteEntry.Type.VIA:
             this._buttonImage.icon_name = 'list-remove-symbolic';
             this._icon.icon_name = 'maps-point-end-symbolic';
             /* Translators: this is remove via location tooltip */
             this._button.tooltip_text = _("Remove via location");
             break;
-        case Type.TO:
+        case RouteEntry.Type.TO:
             this._buttonImage.icon_name = 'route-reverse-symbolic';
             this._icon.icon_name = 'maps-point-end-symbolic';
             /* Translators: this is reverse route tooltip */
@@ -101,12 +99,12 @@ var RouteEntry = GObject.registerClass({
     }
 
     _createEntry() {
-        let entry = new PlaceEntry.PlaceEntry({ visible: true,
-                                                can_focus: true,
-                                                hexpand: true,
-                                                receives_default: true,
-                                                mapView: this._mapView,
-                                                maxChars: 15 });
+        let entry = new PlaceEntry({ visible: true,
+                                     can_focus: true,
+                                     hexpand: true,
+                                     receives_default: true,
+                                     mapView: this._mapView,
+                                     maxChars: 15 });
         if (this._point) {
             entry.bind_property('place',
                                 this._point, 'place',
@@ -115,4 +113,13 @@ var RouteEntry = GObject.registerClass({
 
         return entry;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/route-entry.ui',
+    Children: [ 'iconEventBox' ],
+    InternalChildren: [ 'entryGrid',
+                        'icon',
+                        'button',
+                        'buttonImage' ]
+}, RouteEntry);
diff --git a/src/routeQuery.js b/src/routeQuery.js
index 3b424ec3..8be64c88 100644
--- a/src/routeQuery.js
+++ b/src/routeQuery.js
@@ -19,46 +19,18 @@
  * Author: Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const GObject = imports.gi.GObject;
-const Geocode = imports.gi.GeocodeGlib;
-
-const Application = imports.application;
-const PlaceStore = imports.placeStore;
-const TransitOptions = imports.transitOptions;
-
-var MAX_QUERY_POINTS = 10;
-
-var Transportation = {
-    CAR:        0,
-    BIKE:       1,
-    PEDESTRIAN: 2,
-    TRANSIT:    3,
-
-    toString: function (transportation) {
-        switch(transportation) {
-        case Transportation.CAR:        return 'car';
-        case Transportation.BIKE:       return 'bike';
-        case Transportation.PEDESTRIAN: return 'foot';
-        case Transportation.TRANSIT:    return 'transit';
-        default:                        return null;
-        }
-    }
-};
+import GObject from 'gi://GObject';
+import GeocodeGlib from 'gi://GeocodeGlib';
 
-var QueryPoint = GObject.registerClass({
-    Properties: {
-        'place': GObject.ParamSpec.object('place',
-                                          '',
-                                          '',
-                                          GObject.ParamFlags.READABLE |
-                                          GObject.ParamFlags.WRITABLE,
-                                          Geocode.Place)
-    }
-}, class QueryPoint extends GObject.Object {
+import {Application} from './application.js';
+import {PlaceStore} from './placeStore.js';
+import {TransitOptions} from './transitOptions.js';
+
+export class QueryPoint extends GObject.Object {
 
-    _init() {
+    constructor() {
+        super();
         this._place = null;
-        super._init();
     }
 
     set place(p) {
@@ -69,33 +41,39 @@ var QueryPoint = GObject.registerClass({
     get place() {
         return this._place;
     }
-});
+}
 
-var RouteQuery = GObject.registerClass({
-    Signals: {
-        'reset': { },
-        'point-added': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
-        'point-removed': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
-        'run': { }
-    },
+GObject.registerClass({
     Properties: {
-        'points': GObject.ParamSpec.object('points',
-                                           '',
-                                           '',
-                                           GObject.ParamFlags.READABLE |
-                                           GObject.ParamFlags.WRITABLE,
-                                           GObject.Object),
-        'transportation': GObject.ParamSpec.int('transportation',
-                                                '',
-                                                '',
-                                                GObject.ParamFlags.READABLE |
-                                                GObject.ParamFlags.WRITABLE,
-                                                Transportation.CAR,
-                                                Transportation.PEDESTRIAN,
-                                                Transportation.CAR,
-                                                Transportation.TRANSIT)
+        'place': GObject.ParamSpec.object('place',
+                                          '',
+                                          '',
+                                          GObject.ParamFlags.READABLE |
+                                          GObject.ParamFlags.WRITABLE,
+                                          GeocodeGlib.Place)
+    }
+}, QueryPoint);
+
+export class RouteQuery extends GObject.Object {
+
+    static MAX_QUERY_POINTS = 10;
+
+    static Transportation = {
+        CAR:        0,
+        BIKE:       1,
+        PEDESTRIAN: 2,
+        TRANSIT:    3,
+
+        toString: function (transportation) {
+            switch(transportation) {
+            case RouteQuery.Transportation.CAR:        return 'car';
+            case RouteQuery.Transportation.BIKE:       return 'bike';
+            case RouteQuery.Transportation.PEDESTRIAN: return 'foot';
+            case RouteQuery.Transportation.TRANSIT:    return 'transit';
+            default:                                   return null;
+            }
+        }
     }
-}, class RouteQuery extends GObject.Object {
 
     get points() {
         return this._points;
@@ -163,13 +141,13 @@ var RouteQuery = GObject.registerClass({
         this.notify('points');
     }
 
-    _init(args) {
-        super._init(args);
+    constructor(args) {
+        super(args);
         this._points = [];
         this._time = null;
         this._date = null;
         this._arriveBy = false;
-        this._transitOptions = new TransitOptions.TransitOptions();
+        this._transitOptions = new TransitOptions();
         this._initTransportation();
         this.reset();
     }
@@ -181,7 +159,7 @@ var RouteQuery = GObject.registerClass({
     }
 
     addPoint(index) {
-        if (this._points.length >= MAX_QUERY_POINTS)
+        if (this._points.length >= RouteQuery.MAX_QUERY_POINTS)
             throw new Error('Too many query points');
         let point = new QueryPoint();
 
@@ -251,4 +229,30 @@ var RouteQuery = GObject.registerClass({
         return "\nPoints: " + this.points +
                "\nTransportation: " + this.transportation;
     }
-});
+}
+
+GObject.registerClass({
+    Signals: {
+        'reset': { },
+        'point-added': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
+        'point-removed': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
+        'run': { }
+    },
+    Properties: {
+        'points': GObject.ParamSpec.object('points',
+                                           '',
+                                           '',
+                                           GObject.ParamFlags.READABLE |
+                                           GObject.ParamFlags.WRITABLE,
+                                           GObject.Object),
+        'transportation': GObject.ParamSpec.int('transportation',
+                                                '',
+                                                '',
+                                                GObject.ParamFlags.READABLE |
+                                                GObject.ParamFlags.WRITABLE,
+                                                RouteQuery.Transportation.CAR,
+                                                RouteQuery.Transportation.PEDESTRIAN,
+                                                RouteQuery.Transportation.CAR,
+                                                RouteQuery.Transportation.TRANSIT)
+    }
+}, RouteQuery);
diff --git a/src/routingDelegator.js b/src/routingDelegator.js
index a3f71101..256a06b2 100644
--- a/src/routingDelegator.js
+++ b/src/routingDelegator.js
@@ -19,20 +19,20 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GraphHopper = imports.graphHopper;
-const TransitRouter = imports.transitRouter;
-const RouteQuery = imports.routeQuery;
+import {GraphHopper} from './graphHopper.js';
+import {TransitRouter} from './transitRouter.js';
+import {RouteQuery} from './routeQuery.js';
 
 const _FALLBACK_TRANSPORTATION = RouteQuery.Transportation.PEDESTRIAN;
 
-var RoutingDelegator = class RoutingDelegator {
+export class RoutingDelegator {
 
     constructor(params) {
         this._query = params.query;
 
         this._transitRouting = false;
-        this._graphHopper = new GraphHopper.GraphHopper({ query: this._query });
-        this._transitRouter = new TransitRouter.TransitRouter({ query: this._query });
+        this._graphHopper = new GraphHopper({ query: this._query });
+        this._transitRouter = new TransitRouter({ query: this._query });
         this._query.connect('notify::points', this._onQueryChanged.bind(this));
 
         /* if the query is set to transit mode when it's not available, revert
@@ -74,4 +74,4 @@ var RoutingDelegator = class RoutingDelegator {
             }
         }
     }
-};
+}
diff --git a/src/searchPopover.js b/src/searchPopover.js
index 64c9f229..cb184b21 100644
--- a/src/searchPopover.js
+++ b/src/searchPopover.js
@@ -20,18 +20,16 @@
  *         Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
 /* Abstract search result popover that progagates keypress events from a
    focus-taking internal widget to the spawning search entry widget */
-var SearchPopover = GObject.registerClass({
-    Abstract: true
-}, class SearchPopover extends Gtk.Popover {
+export class SearchPopover extends Gtk.Popover {
 
-    _init(props) {
-        super._init(props);
+    constructor(props) {
+        super(props);
 
         this._entry = this.relative_to;
 
@@ -110,5 +108,9 @@ var SearchPopover = GObject.registerClass({
             adjustment.clamp_page(allocation.y, allocation.y + allocation.height);
         }
     }
-});
+}
+
+GObject.registerClass({
+    Abstract: true
+}, SearchPopover);
 
diff --git a/src/sendToDialog.js b/src/sendToDialog.js
index 202cb9f7..435b7b37 100644
--- a/src/sendToDialog.js
+++ b/src/sendToDialog.js
@@ -17,62 +17,50 @@
  * Author: Jonas Danielson <jonas threetimestwo org>
  */
 
-const Gdk = imports.gi.Gdk;
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const GWeather = imports.gi.GWeather;
-const Soup = imports.gi.Soup;
-
-const Application = imports.application;
-const PlaceFormatter = imports.placeFormatter;
-const Utils = imports.utils;
+import Gdk from 'gi://Gdk';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import GWeather from 'gi://GWeather';
+import Soup from 'gi://Soup';
+
+import {Application} from './application.js';
+import {PlaceFormatter} from './placeFormatter.js';
+import * as Utils from './utils.js';
 
 const _WEATHER_APPID = 'org.gnome.Weather';
 const _CLOCKS_APPID = 'org.gnome.clocks';
 
-var Response = {
-    SUCCESS: 0,
-    CANCEL: 1
-};
-
 const _NUM_VISIBLE = 4;
 
-var SendToDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/send-to-dialog.ui',
-    InternalChildren: [ 'list',
-                        'weatherRow',
-                        'weatherLabel',
-                        'weatherIcon',
-                        'clocksRow',
-                        'clocksLabel',
-                        'clocksIcon',
-                        'cancelButton',
-                        'summaryLabel',
-                        'summaryUrl',
-                        'copyButton',
-                        'emailButton',
-                        'scrolledWindow' ]
-}, class SendToDialog extends Gtk.Dialog {
+export class SendToDialog extends Gtk.Dialog {
 
-    _init(params) {
-        this._place = params.place;
-        this._location = this._place.location;
+    static Response = {
+        SUCCESS: 0,
+        CANCEL: 1
+    };
+
+    constructor(params) {
+        let place = params.place;
         delete params.place;
 
-        this._mapView = params.mapView;
+        let mapView = params.mapView;
         delete params.mapView;
 
         params.use_header_bar = true;
-        super._init(params);
+        super(params);
+
+        this._place = place;
+        this._location = this._place.location;
+        this._mapView = mapView;
 
         this._scrolledWindow.min_content_height = 40 * _NUM_VISIBLE;
         this.get_header_bar().subtitle = this._place.name;
 
         this._cancelButton.connect('clicked',
-                                   () => this.response(Response.CANCEL));
+                                   () => this.response(SendToDialog.Response.CANCEL));
 
         this._list.connect('row-activated', (list, row) => this._activateRow(row));
 
@@ -148,7 +136,7 @@ var SendToDialog = GObject.registerClass({
         let place = this._place;
         let lines = [];
 
-        let formatter = new PlaceFormatter.PlaceFormatter(place);
+        let formatter = new PlaceFormatter(place);
 
         if (!place.isCurrentLocation)
             lines.push(formatter.title);
@@ -187,11 +175,11 @@ var SendToDialog = GObject.registerClass({
         let display = Gdk.Display.get_default();
         let clipboard = Gtk.Clipboard.get_default(display);
         clipboard.set_text(summary, -1);
-        this.response(Response.SUCCESS);
+        this.response(SendToDialog.Response.SUCCESS);
     }
 
     _emailSummary() {
-        let title = new PlaceFormatter.PlaceFormatter(this._place).title;
+        let title = new PlaceFormatter(this._place).title;
         let summary = "%s\n%s".format(this._getSummary(), this._getOSMURI());
         let uri = 'mailto:?subject=%s&body=%s'.format(Soup.URI.encode(title, null),
                                                       Soup.URI.encode(summary, null));
@@ -204,7 +192,7 @@ var SendToDialog = GObject.registerClass({
           Utils.debug('failed to open URI: %s'.format(e.message));
         }
 
-        this.response(Response.SUCCESS);
+        this.response(SendToDialog.Response.SUCCESS);
     }
 
     _getAppLaunchContext() {
@@ -238,25 +226,44 @@ var SendToDialog = GObject.registerClass({
                                  new GLib.Variant('v', this._city.serialize()),
                                  timestamp);
         } else if (row instanceof OpenWithRow) {
-            let uri = this._location.to_uri(Geocode.LocationURIScheme.GEO);
+            let uri = this._location.to_uri(GeocodeGlib.LocationURIScheme.GEO);
             row.appinfo.launch_uris([ uri ], this._getAppLaunchContext());
         }
-        this.response(Response.SUCCESS);
+        this.response(SendToDialog.Response.SUCCESS);
     }
-});
+}
 
-var OpenWithRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/open-with-row.ui',
-    InternalChildren: [ 'label',
-                        'icon' ],
-}, class OpenWithRow extends Gtk.ListBoxRow {
-    _init(params) {
-        this.appinfo = params.appinfo;
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/send-to-dialog.ui',
+    InternalChildren: [ 'list',
+                        'weatherRow',
+                        'weatherLabel',
+                        'weatherIcon',
+                        'clocksRow',
+                        'clocksLabel',
+                        'clocksIcon',
+                        'cancelButton',
+                        'summaryLabel',
+                        'summaryUrl',
+                        'copyButton',
+                        'emailButton',
+                        'scrolledWindow' ]
+}, SendToDialog);
+
+export class OpenWithRow extends Gtk.ListBoxRow {
+    constructor(params) {
+        let appinfo = params.appinfo;
         delete params.appinfo;
 
-        super._init(params);
+        super(params);
 
-        this._label.label = _("Open with %s").format(this.appinfo.get_name());
-        this._icon.gicon = this.appinfo.get_icon();
+        this._label.label = _("Open with %s").format(appinfo.get_name());
+        this._icon.gicon = appinfo.get_icon();
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/open-with-row.ui',
+    InternalChildren: [ 'label',
+                        'icon' ],
+}, OpenWithRow);
diff --git a/src/service.js b/src/service.js
index e0e2e799..2bae10c1 100644
--- a/src/service.js
+++ b/src/service.js
@@ -19,11 +19,11 @@
  *         Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
-const Utils = imports.utils;
+import * as Utils from './utils.js';
 
 let _service = null;
 
@@ -46,7 +46,7 @@ function _createDefaultService() {
     return _getServiceFromFile(filename);
 }
 
-function getService() {
+export function getService() {
     if (_service)
         return _service;
 
diff --git a/src/settings.js b/src/settings.js
index fa2478ab..ddeb02ff 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -19,16 +19,41 @@
  * Author: Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const GLib = imports.gi.GLib;
-const Gio = imports.gi.Gio;
-const GObject = imports.gi.GObject;
-const System = imports.system;
+import GLib from 'gi://GLib';
+import Gio from 'gi://Gio';
+import GObject from 'gi://GObject';
+import * as system from 'system';
 
-var Settings = GObject.registerClass(
-class Settings extends Gio.Settings {
+export class Settings extends Gio.Settings {
 
-    _init(params) {
-        super._init(params);
+    static getSettings(schemaId, path) {
+        const GioSSS = Gio.SettingsSchemaSource;
+        let schemaSource;
+
+        if (!pkg.moduledir.startsWith('resource://')) {
+            // Running from the source tree
+            schemaSource = GioSSS.new_from_directory(pkg.pkgdatadir,
+                                                     GioSSS.get_default(),
+                                                     false);
+        } else {
+            schemaSource = GioSSS.get_default();
+        }
+
+        let schemaObj = schemaSource.lookup(schemaId, true);
+        if (!schemaObj) {
+            log('Missing GSettings schema ' + schemaId);
+            system.exit(1);
+        }
+
+        if (path === undefined)
+            return new Settings({ settings_schema: schemaObj });
+        else
+            return new Settings({ settings_schema: schemaObj,
+                                  path: path });
+    }
+
+    constructor(params) {
+        super(params);
         // The GVariant types of the settings
         this._keyTypes = {};
         this.list_keys().forEach((key) => {
@@ -45,30 +70,6 @@ class Settings extends Gio.Settings {
     set(name, value) {
         this.set_value(name, GLib.Variant.new (this._keyTypes[name], value));
     }
-});
-
-function getSettings(schemaId, path) {
-    const GioSSS = Gio.SettingsSchemaSource;
-    let schemaSource;
-
-    if (!pkg.moduledir.startsWith('resource://')) {
-        // Running from the source tree
-        schemaSource = GioSSS.new_from_directory(pkg.pkgdatadir,
-                                                 GioSSS.get_default(),
-                                                 false);
-    } else {
-        schemaSource = GioSSS.get_default();
-    }
-
-    let schemaObj = schemaSource.lookup(schemaId, true);
-    if (!schemaObj) {
-        log('Missing GSettings schema ' + schemaId);
-        System.exit(1);
-    }
-
-    if (path === undefined)
-        return new Settings({ settings_schema: schemaObj });
-    else
-        return new Settings({ settings_schema: schemaObj,
-                              path: path });
 }
+
+GObject.registerClass(Settings);
diff --git a/src/shapeLayer.js b/src/shapeLayer.js
index 7d42c9b4..18ac5170 100644
--- a/src/shapeLayer.js
+++ b/src/shapeLayer.js
@@ -17,31 +17,32 @@
  * Author: Hashem Nasarat <hashem riseup net>
  */
 
-const Champlain = imports.gi.Champlain;
-const Gio = imports.gi.Gio;
-const GObject = imports.gi.GObject;
+import Champlain from 'gi://Champlain';
+import Gio from 'gi://Gio';
+import GObject from 'gi://GObject';
 
-const GeoJSONShapeLayer = imports.geoJSONShapeLayer;
-const Utils = imports.utils;
+import {GeoJSONShapeLayer} from './geoJSONShapeLayer.js';
+import * as Utils from './utils.js';
 
-var SUPPORTED_TYPES = [];
+export class ShapeLayer extends GObject.Object {
 
-function newFromFile(file, mapView) {
-    let contentType = Gio.content_type_guess(file.get_uri(), null)[0];
-    for (let layerClass of SUPPORTED_TYPES) {
-        if (layerClass.mimeTypes.indexOf(contentType) > -1) {
-            return layerClass.createInstance({ file: file, mapView: mapView });
+    static mimeTypes = [];
+    static displayName = '';
+
+    static SUPPORTED_TYPES = [];
+
+    static newFromFile(file, mapView) {
+        let contentType = Gio.content_type_guess(file.get_uri(), null)[0];
+        for (let layerClass of ShapeLayer.SUPPORTED_TYPES) {
+            if (layerClass.mimeTypes.indexOf(contentType) > -1) {
+                return layerClass.createInstance({ file: file, mapView: mapView });
+            }
         }
+        return null;
     }
-    return null;
-}
 
-var ShapeLayer = GObject.registerClass({
-    Abstract: true
-}, class ShapeLayer extends GObject.Object {
-
-    _init(params) {
-        super._init();
+    constructor(params) {
+        super();
         this._visible = true;
         this._mapView = params.mapView;
         this.file = params.file;
@@ -112,7 +113,9 @@ var ShapeLayer = GObject.registerClass({
         this._mapView.view.remove_layer(this._markerLayer);
         this._mapView.view.remove_overlay_source(this._mapSource);
     }
-});
+}
+
+GObject.registerClass({
+    Abstract: true
+}, ShapeLayer);
 
-ShapeLayer.mimeTypes = [];
-ShapeLayer.displayName = '';
diff --git a/src/shortPrintLayout.js b/src/shortPrintLayout.js
index a926afdb..80067710 100644
--- a/src/shortPrintLayout.js
+++ b/src/shortPrintLayout.js
@@ -17,9 +17,9 @@
  * Author: Amisha Singla <amishas157 gmail com>
  */
 
-const GObject = imports.gi.GObject;
+import GObject from 'gi://GObject';
 
-const PrintLayout = imports.printLayout;
+import {PrintLayout} from './printLayout.js';
 
 /* All following constants are ratios of surface size to page size */
 const _Instruction = {
@@ -28,17 +28,18 @@ const _Instruction = {
     SCALE_MARGIN: 0.01
 };
 
-var ShortPrintLayout = GObject.registerClass(
-class ShortPrintLayout extends PrintLayout.PrintLayout {
-    _init(params) {
-        this._route = params.route;
+export class ShortPrintLayout extends PrintLayout {
+    constructor(params) {
+        let route = params.route;
         delete params.route;
 
         /* (Header +  map) + instructions */
         let totalSurfaces = 2 + this._route.turnPoints.length;
         params.totalSurfaces = totalSurfaces;
 
-        super._init(params);
+        super(params);
+
+        this._route = route;
     }
 
     render() {
@@ -56,4 +57,6 @@ class ShortPrintLayout extends PrintLayout.PrintLayout {
             this._cursorY += dy;
         });
     }
-});
+}
+
+GObject.registerClass(ShortPrintLayout);
diff --git a/src/sidebar.js b/src/sidebar.js
index 3e97e3dc..b8df6216 100644
--- a/src/sidebar.js
+++ b/src/sidebar.js
@@ -20,56 +20,29 @@
  *         Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const Cairo = imports.cairo;
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Cairo from 'cairo';
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const InstructionRow = imports.instructionRow;
-const PlaceStore  = imports.placeStore;
-const RouteEntry = imports.routeEntry;
-const RouteQuery = imports.routeQuery;
-const StoredRoute = imports.storedRoute;
-const TransitArrivalRow = imports.transitArrivalRow;
-const TransitItineraryRow = imports.transitItineraryRow;
-const TransitLegRow = imports.transitLegRow;
-const TransitMoreRow = imports.transitMoreRow;
-const TransitOptionsPanel = imports.transitOptionsPanel;
-const Utils = imports.utils;
-
-var Sidebar = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/sidebar.ui',
-    InternalChildren: [ 'distanceInfo',
-                        'entryList',
-                        'instructionList',
-                        'instructionWindow',
-                        'instructionSpinner',
-                        'instructionStack',
-                        'errorLabel',
-                        'modeBikeToggle',
-                        'modeCarToggle',
-                        'modePedestrianToggle',
-                        'modeTransitToggle',
-                        'timeInfo',
-                        'linkButtonStack',
-                        'transitWindow',
-                        'transitRevealer',
-                        //'transitOptionsPanel',
-                        'transitHeader',
-                        'transitListStack',
-                        'transitOverviewListBox',
-                        'transitItineraryHeader',
-                        'transitItineraryListBox',
-                        'transitItineraryBackButton',
-                        'transitItineraryTimeLabel',
-                        'transitItineraryDurationLabel',
-                        'transitAttributionLabel']
-}, class Sidebar extends Gtk.Revealer {
+import {Application} from './application.js';
+import {InstructionRow} from './instructionRow.js';
+import {PlaceStore} from './placeStore.js';
+import {RouteEntry} from './routeEntry.js';
+import {RouteQuery} from './routeQuery.js';
+import {StoredRoute} from './storedRoute.js';
+import {TransitArrivalRow} from './transitArrivalRow.js';
+import {TransitItineraryRow} from './transitItineraryRow.js';
+import {TransitLegRow} from './transitLegRow.js';
+import {TransitMoreRow} from './transitMoreRow.js';
+import {TransitOptionsPanel} from './transitOptionsPanel.js';
+import * as Utils from './utils.js';
+
+export class Sidebar extends Gtk.Revealer {
 
-    _init(mapView) {
-        super._init({ transition_type: Gtk.RevealerTransitionType.SLIDE_LEFT });
+    constructor(mapView) {
+        super({ transition_type: Gtk.RevealerTransitionType.SLIDE_LEFT });
 
         this._mapView = mapView;
 
@@ -81,8 +54,7 @@ var Sidebar = GObject.registerClass({
          * itinerary header widget into the GtkStack to get the correct
          * animation direction.
          */
-        this._transitOptionsPanel =
-            new TransitOptionsPanel.TransitOptionsPanel({ visible: true });
+        this._transitOptionsPanel = new TransitOptionsPanel({ visible: true });
         this._transitHeader.add_named(this._transitOptionsPanel, 'options');
         this._transitHeader.add_named(this._transitItineraryHeader,
                                       'itinerary-header');
@@ -181,9 +153,9 @@ var Sidebar = GObject.registerClass({
         else
             type = RouteEntry.Type.VIA;
 
-        let routeEntry = new RouteEntry.RouteEntry({ type: type,
-                                                     point: point,
-                                                     mapView: this._mapView });
+        let routeEntry = new RouteEntry({ type: type,
+                                          point: point,
+                                          mapView: this._mapView });
 
         // add handler overriding tab focus behavior on route entries
         routeEntry.entry.connect('focus', this._onRouteEntryFocus.bind(this));
@@ -331,7 +303,7 @@ var Sidebar = GObject.registerClass({
                 let places = this._query.filledPoints.map(function(point) {
                     return point.place;
                 });
-                let storedRoute = new StoredRoute.StoredRoute({
+                let storedRoute = new StoredRoute({
                     transportation: this._query.transportation,
                     route: route,
                     places: places,
@@ -346,8 +318,8 @@ var Sidebar = GObject.registerClass({
             });
 
             route.turnPoints.forEach((turnPoint) => {
-                let row = new InstructionRow.InstructionRow({ visible: true,
-                                                              turnPoint: turnPoint });
+                let row = new InstructionRow({ visible: true,
+                                               turnPoint: turnPoint });
                 this._instructionList.insert(row, -1);
             });
 
@@ -438,14 +410,13 @@ var Sidebar = GObject.registerClass({
         let plan = Application.routingDelegator.transitRouter.plan;
 
         plan.itineraries.forEach((itinerary) => {
-            let row =
-                new TransitItineraryRow.TransitItineraryRow({ visible: true,
-                                                              itinerary: itinerary });
+            let row = new TransitItineraryRow({ visible: true,
+                                                itinerary: itinerary });
             this._transitOverviewListBox.insert(row, -1);
         });
         /* add the "load more" row */
-        this._transitOverviewListBox.insert(
-            new TransitMoreRow.TransitMoreRow({ visible: true }), -1);
+        this._transitOverviewListBox.insert(new TransitMoreRow({ visible: true }),
+                                            -1);
 
         /* add an empty list row to get a final separator */
         this._transitOverviewListBox.insert(new Gtk.ListBoxRow({ visible: true }),
@@ -483,16 +454,15 @@ var Sidebar = GObject.registerClass({
         this._clearTransitItinerary();
         for (let i = 0; i < itinerary.legs.length; i++) {
             let leg = itinerary.legs[i];
-            let row = new TransitLegRow.TransitLegRow({ leg: leg,
-                                                        start: i === 0,
-                                                        mapView: this._mapView });
+            let row = new TransitLegRow({ leg: leg,
+                                          start: i === 0,
+                                          mapView: this._mapView });
             this._transitItineraryListBox.insert(row, -1);
         }
 
         /* insert the additional arrival row, showing the arrival place and time */
         this._transitItineraryListBox.insert(
-            new TransitArrivalRow.TransitArrivalRow({ itinerary: itinerary,
-                                                      mapView: this._mapView }),
+            new TransitArrivalRow({ itinerary: itinerary, mapView: this._mapView }),
             -1);
     }
 
@@ -627,4 +597,33 @@ var Sidebar = GObject.registerClass({
         row.connect('drag-motion', this._onDragMotion.bind(this));
         row.connect('drag-drop', this._onDragDrop.bind(this));
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/sidebar.ui',
+    InternalChildren: [ 'distanceInfo',
+                        'entryList',
+                        'instructionList',
+                        'instructionWindow',
+                        'instructionSpinner',
+                        'instructionStack',
+                        'errorLabel',
+                        'modeBikeToggle',
+                        'modeCarToggle',
+                        'modePedestrianToggle',
+                        'modeTransitToggle',
+                        'timeInfo',
+                        'linkButtonStack',
+                        'transitWindow',
+                        'transitRevealer',
+                        //'transitOptionsPanel',
+                        'transitHeader',
+                        'transitListStack',
+                        'transitOverviewListBox',
+                        'transitItineraryHeader',
+                        'transitItineraryListBox',
+                        'transitItineraryBackButton',
+                        'transitItineraryTimeLabel',
+                        'transitItineraryDurationLabel',
+                        'transitAttributionLabel']
+}, Sidebar);
diff --git a/src/storedRoute.js b/src/storedRoute.js
index 04763097..1fbfef3f 100644
--- a/src/storedRoute.js
+++ b/src/storedRoute.js
@@ -20,29 +20,37 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Champlain = imports.gi.Champlain;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Champlain from 'gi://Champlain';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Place = imports.place;
-const Route = imports.route;
-const RouteQuery = imports.routeQuery;
+import {Place} from './place.js';
+import {Route, TurnPoint} from './route.js';
+import {RouteQuery} from './routeQuery.js';
 
 // directional override markers
 const _RLM = '\u200F';
 const _LRM = '\u200E';
 
-var StoredRoute = GObject.registerClass(
-class StoredRoute extends Place.Place {
+export class StoredRoute extends Place {
 
-    _init(params) {
+    constructor(params) {
         let route = params.route;
         delete params.route;
 
-        this._transportation = params.transportation;
+        let transportation = params.transportation;
         delete params.transportation;
 
-        this.route = new Route.Route();
+        let places = params.places;
+        delete params.places;
+
+        let geoclue = params.geoclue;
+        delete params.geoclue;
+
+        super(params);
+
+        this._transportation = transportation;
+        this.route = new Route();
         this.route.update({ path: route.path,
                             turnPoints: route.turnPoints,
                             distance: route.distance,
@@ -51,17 +59,12 @@ class StoredRoute extends Place.Place {
 
         this._rtl = Gtk.get_locale_direction() === Gtk.TextDirection.RTL;
 
-        this.places = params.places;
-        delete params.places;
+        this.places = places;
         let directionMarker = this._rtl ? _RLM : _LRM;
         let arrow = this._rtl ? '←' : '→';
         params.name = directionMarker + this.places[0].name + directionMarker +
                       arrow + directionMarker + this.places.last().name;
 
-
-        let geoclue = params.geoclue;
-        delete params.geoclue;
-
         this._containsCurrentLocation = false;
 
         let currentLocation = null;
@@ -72,8 +75,6 @@ class StoredRoute extends Place.Place {
             if (currentLocation && place === currentLocation)
                 this._containsCurrentLocation = true;
         });
-
-        super._init(params);
     }
 
     get viaString() {
@@ -154,53 +155,55 @@ class StoredRoute extends Place.Place {
                  route: route,
                  places: places };
     }
-});
-
-StoredRoute.fromJSON = function(obj) {
-    let props;
-    let places = [];
-    let route;
-    let transportation = null;
-
-    for (let key in obj) {
-        let prop = obj[key];
-
-        switch(key) {
-        case 'transportation':
-            transportation = prop;
-            break;
-
-        case 'route':
-            route = new Route.Route();
-            prop.path = prop.path.map((coordinate) => {
-                let lat = coordinate.latitude;
-                let lon = coordinate.longitude;
-                return new Champlain.Coordinate({ latitude: lat,
-                                                  longitude: lon });
-            });
-            prop.turnPoints = prop.turnPoints.map((turnPoint) => {
-                let lat = turnPoint.coordinate.latitude;
-                let lon = turnPoint.coordinate.longitude;
-
-                let coordinate = new Champlain.Coordinate({ latitude: lat,
-                                                            longitude: lon });
-
-                return new Route.TurnPoint({
-                    coordinate: coordinate,
-                    type: turnPoint.type,
-                    distance: turnPoint.distance,
-                    instruction: turnPoint.instruction
+
+    static fromJSON(obj) {
+        let props;
+        let places = [];
+        let route;
+        let transportation = null;
+
+        for (let key in obj) {
+            let prop = obj[key];
+
+            switch(key) {
+            case 'transportation':
+                transportation = prop;
+                break;
+
+            case 'route':
+                route = new Route();
+                prop.path = prop.path.map((coordinate) => {
+                    let lat = coordinate.latitude;
+                    let lon = coordinate.longitude;
+                    return new Champlain.Coordinate({ latitude: lat,
+                                                      longitude: lon });
                 });
-            });
-            route.update(prop);
-            break;
+                prop.turnPoints = prop.turnPoints.map((turnPoint) => {
+                    let lat = turnPoint.coordinate.latitude;
+                    let lon = turnPoint.coordinate.longitude;
+
+                    let coordinate = new Champlain.Coordinate({ latitude: lat,
+                                                                longitude: lon });
+
+                    return new TurnPoint({
+                        coordinate: coordinate,
+                        type: turnPoint.type,
+                        distance: turnPoint.distance,
+                        instruction: turnPoint.instruction
+                    });
+                });
+                route.update(prop);
+                break;
 
-        case 'places':
-            prop.forEach((p) => places.push(Place.Place.fromJSON(p)));
-            break;
+            case 'places':
+                prop.forEach((p) => places.push(Place.fromJSON(p)));
+                break;
+            }
         }
+        return new StoredRoute({ transportation: transportation,
+                                 route: route,
+                                 places: places });
     }
-    return new StoredRoute({ transportation: transportation,
-                             route: route,
-                             places: places });
-};
+}
+
+GObject.registerClass(StoredRoute);
diff --git a/src/time.js b/src/time.js
index 0c19400b..b2970cc6 100644
--- a/src/time.js
+++ b/src/time.js
@@ -19,7 +19,7 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Gio = imports.gi.Gio;
+import Gio from 'gi://Gio';
 
 // allow using :, ., and the ratio symbol to separate hours:mins
 const _DELIMITERS = [':', '.', '\u2236'];
@@ -105,7 +105,7 @@ const _timeFormat12 = new Intl.DateTimeFormat([], { hour:     '2-digit',
  *
  * TODO: maybe try to use some library to get better locale handling,
  * or push for something in GLib */
-function parseTimeString(timeString) {
+export function parseTimeString(timeString) {
     let pmSet = false;
     let hours;
     let mins;
@@ -176,17 +176,22 @@ function parseTimeString(timeString) {
     }
 }
 
-function _is12Hour() {
+let _is12Hour = function() {
     return _clockFormat === '12h';
 }
 
+// for use by unit test mocking only
+export function _setIs12HourFunction(f) {
+    _is12Hour = f;
+}
+
 /**
  * Format a time as HH:mm in either 12 or 24 h
  * format depending on system settings
  * given time in ms since Epoch with an offset in
  * ms relative UTC.
  */
-function formatTimeWithTZOffset(time, offset) {
+export function formatTimeWithTZOffset(time, offset) {
     let utcTimeWithOffset = time + offset;
     let date = new Date();
     let timeFormat = _is12Hour() ? _timeFormat12 : _timeFormat24;
@@ -201,7 +206,7 @@ function formatTimeWithTZOffset(time, offset) {
  * format depending on system settings
  * given hours and minutes values.
  */
-function formatTimeFromHoursAndMins(hours, mins) {
+export function formatTimeFromHoursAndMins(hours, mins) {
     let date = new Date();
     let timeFormat = _is12Hour() ? _timeFormat12 : _timeFormat24;
 
diff --git a/src/togeojson/togeojson.js b/src/togeojson/togeojson.js
index ee99627f..f725bfa1 100644
--- a/src/togeojson/togeojson.js
+++ b/src/togeojson/togeojson.js
@@ -1,6 +1,6 @@
-const Dom = imports.xmldom.dom;
+import * as Dom from '../xmldom/dom.js';
 
-var toGeoJSON = (function() {
+export var toGeoJSON = (function() {
     'use strict';
 
     var removeSpace = /\s*/g,
diff --git a/src/transit.js b/src/transit.js
index 936847e5..3c4ff67c 100644
--- a/src/transit.js
+++ b/src/transit.js
@@ -19,16 +19,18 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const Utils = imports.utils;
+import * as Utils from './utils.js';
+
+const _ = gettext.gettext;
 
 /**
  * Get the label to display for the starting point of an itinerary leg.
  * leg: the itinerary leg
  * isFirstLeg: true if this is the first leg of the itinerary.
  */
-function getFromLabel(leg, isFirstLeg) {
+export function getFromLabel(leg, isFirstLeg) {
     if (isFirstLeg) {
         if (leg.from) {
             /* Translators: this is a format string indicating instructions
@@ -51,7 +53,7 @@ function getFromLabel(leg, isFirstLeg) {
  * Get the label to display for the destination headsign.
  * leg: the itinerary leg
  */
-function getHeadsignLabel(leg) {
+export function getHeadsignLabel(leg) {
     if (leg.transit && leg.headsign) {
         return leg.headsign;
     } else if (!leg.transit) {
@@ -67,7 +69,7 @@ function getHeadsignLabel(leg) {
 /**
  * Get the label to display for arrival of the final leg of an itinerary.
  */
-function getArrivalLabel(lastLeg) {
+export function getArrivalLabel(lastLeg) {
     if (lastLeg.to) {
         /* Translators: this a format string indicating arriving at the
          * destination of journey with the arrival address and transit
diff --git a/src/transitArrivalMarker.js b/src/transitArrivalMarker.js
index 62547400..506b3905 100644
--- a/src/transitArrivalMarker.js
+++ b/src/transitArrivalMarker.js
@@ -19,30 +19,27 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
 
-const Color = imports.color;
-const Location = imports.location;
-const MapMarker = imports.mapMarker;
-const Place = imports.place;
+import * as Color from './color.js';
+import {Location} from './location.js';
+import {MapMarker} from './mapMarker.js';
+import {Place} from './place.js';
+import * as TransitPlan from './transitPlan.js';
 
-var TransitArrivalMarker = GObject.registerClass(
-class TransitArrivalMarker extends MapMarker.MapMarker {
+export class TransitArrivalMarker extends MapMarker {
 
-    _init(params) {
+    constructor(params) {
         let lastPoint = params.leg.polyline[params.leg.polyline.length - 1];
-        let location =
-            new Location.Location({ latitude: lastPoint.latitude,
-                                    longitude: lastPoint.longitude
-                                  });
-        let bgColor = params.leg.color ? params.leg.color :
-                                         TransitPlan.DEFAULT_ROUTE_COLOR;
+        let location = new Location({ latitude: lastPoint.latitude,
+                                      longitude: lastPoint.longitude });
+        let bgColor = params.leg.color ?? TransitPlan.DEFAULT_ROUTE_COLOR;
 
         delete params.leg;
-        params.place = new Place.Place({ location: location });
+        params.place = new Place({ location: location });
 
-        super._init(params);
+        super(params);
 
         let bgRed = Color.parseColor(bgColor, 0);
         let bgGreen = Color.parseColor(bgColor, 1);
@@ -62,4 +59,6 @@ class TransitArrivalMarker extends MapMarker.MapMarker {
         return { x: Math.floor(this.width / 2) - 1,
                  y: Math.floor(this.height / 2) - 1 };
     }
-});
+}
+
+GObject.registerClass(TransitArrivalMarker);
diff --git a/src/transitArrivalRow.js b/src/transitArrivalRow.js
index bb5333db..023134ed 100644
--- a/src/transitArrivalRow.js
+++ b/src/transitArrivalRow.js
@@ -19,31 +19,25 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Transit = imports.transit;
+import * as Transit from './transit.js';
 
-var TransitArrivalRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/transit-arrival-row.ui',
-    InternalChildren: ['arrivalLabel',
-                       'timeLabel',
-                       'eventBox',
-                       'separator']
-}, class TransitArrivalRow extends Gtk.ListBoxRow {
+export class TransitArrivalRow extends Gtk.ListBoxRow {
 
-    _init(params) {
-        this._itinerary = params.itinerary;
+    constructor(params) {
+        let itinerary = params.itinerary;
         delete params.itinerary;
 
-        this._mapView = params.mapView;
+        let mapView = params.mapView;
         delete params.mapView;
 
-        super._init(params);
-
-        let lastLeg = this._itinerary.legs[this._itinerary.legs.length - 1];
+        super(params);
+        let lastLeg = itinerary.legs[itinerary.legs.length - 1];
 
+        this._mapView = mapView;
         this._arrivalLabel.label = Transit.getArrivalLabel(lastLeg);
         this._timeLabel.label = lastLeg.prettyPrintArrivalTime();
 
@@ -62,4 +56,12 @@ var TransitArrivalRow = GObject.registerClass({
             this._mapView.view.center_on(coord[0], coord[1]);
         }
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/transit-arrival-row.ui',
+    InternalChildren: ['arrivalLabel',
+                       'timeLabel',
+                       'eventBox',
+                       'separator']
+}, TransitArrivalRow);
diff --git a/src/transitBoardMarker.js b/src/transitBoardMarker.js
index 2409614e..462727c4 100644
--- a/src/transitBoardMarker.js
+++ b/src/transitBoardMarker.js
@@ -19,18 +19,18 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Cairo = imports.cairo;
-const Clutter = imports.gi.Clutter;
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-
-const Color = imports.color;
-const Location = imports.location;
-const MapMarker = imports.mapMarker;
-const Place = imports.place;
-const TransitPlan = imports.transitPlan;
-const Utils = imports.utils;
+import Cairo from 'cairo';
+import Clutter from 'gi://Clutter';
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+
+import * as Color from './color.js';
+import {Location} from './location.js';
+import {MapMarker} from './mapMarker.js';
+import {Place} from './place.js';
+import * as TransitPlan from './transitPlan.js';
+import * as Utils from './utils.js';
 
 const ICON_SIZE = 12;
 const ACTOR_SIZE = 20;
@@ -40,19 +40,17 @@ const ACTOR_SIZE = 20;
  */
 const OUTLINE_LUMINANCE_THREASHHOLD = 0.9;
 
-var TransitBoardMarker = GObject.registerClass(
-class TransitBoardMarker extends MapMarker.MapMarker {
+export class TransitBoardMarker extends MapMarker {
 
-    _init(params) {
+    constructor(params) {
         let firstPoint = params.leg.polyline[0];
-        let location = new Location.Location({ latitude: firstPoint.latitude,
-                                               longitude: firstPoint.longitude
-                                             });
+        let location = new Location({ latitude: firstPoint.latitude,
+                                      longitude: firstPoint.longitude });
         let leg = params.leg;
 
         delete params.leg;
-        params.place = new Place.Place({ location: location });
-        super._init(params);
+        params.place = new Place({ location: location });
+        super(params);
 
         this.add_actor(this._createActor(leg));
     }
@@ -68,7 +66,7 @@ class TransitBoardMarker extends MapMarker.MapMarker {
      */
     _createActor(leg) {
         try {
-            let bgColor = leg.color ? leg.color : TransitPlan.DEFAULT_ROUTE_COLOR;
+            let bgColor = leg.color ?? TransitPlan.DEFAULT_ROUTE_COLOR;
             let fgColor =
                 Color.getContrastingForegroundColor(bgColor, leg.textColor ?
                                                              leg.textColor :
@@ -135,4 +133,6 @@ class TransitBoardMarker extends MapMarker.MapMarker {
         return { x: Math.floor(this.width / 2) - 1,
                  y: Math.floor(this.height / 2) - 1 };
     }
-});
+}
+
+GObject.registerClass(TransitBoardMarker);
diff --git a/src/transitItineraryRow.js b/src/transitItineraryRow.js
index 0ec2db3f..9ae2594e 100644
--- a/src/transitItineraryRow.js
+++ b/src/transitItineraryRow.js
@@ -19,27 +19,23 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const TransitRouteLabel = imports.transitRouteLabel;
+import {TransitRouteLabel} from './transitRouteLabel.js';
 
 // maximum number of legs to show before abbreviating with a … in the middle
 const MAX_LEGS_SHOWN = 8;
 
-var TransitItineraryRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/transit-itinerary-row.ui',
-    InternalChildren: ['timeLabel',
-                       'durationLabel',
-                       'summaryGrid']
-}, class TransitItineraryRow extends Gtk.ListBoxRow {
+export class TransitItineraryRow extends Gtk.ListBoxRow {
 
-    _init(params) {
-        this._itinerary = params.itinerary;
+    constructor(params) {
+        let itinerary = params.itinerary;
         delete params.itinerary;
 
-        super._init(params);
+        super(params);
 
+        this._itinerary = itinerary;
         this._timeLabel.label = this._itinerary.prettyPrintTimeInterval();
         this._durationLabel.label = this._itinerary.prettyPrintDuration();
 
@@ -137,12 +133,19 @@ var TransitItineraryRow = GObject.registerClass({
             let grid = new Gtk.Grid({ visible: true, column_spacing: 2 });
 
             grid.attach(icon, 0, 0, 1, 1);
-            grid.attach(new TransitRouteLabel.TransitRouteLabel({ leg: leg,
-                                                                  compact: useCompact,
-                                                                  visible: true }),
+            grid.attach(new TransitRouteLabel({ leg: leg,
+                                                compact: useCompact,
+                                                visible: true }),
                         1, 0, 1, 1);
 
             return grid;
         }
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/transit-itinerary-row.ui',
+    InternalChildren: ['timeLabel',
+                       'durationLabel',
+                       'summaryGrid']
+}, TransitItineraryRow);
diff --git a/src/transitLegRow.js b/src/transitLegRow.js
index 46d0a31d..371dacab 100644
--- a/src/transitLegRow.js
+++ b/src/transitLegRow.js
@@ -19,54 +19,44 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const Gdk = imports.gi.Gdk;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Pango = imports.gi.Pango;
+import Gdk from 'gi://Gdk';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Pango from 'gi://Pango';
 
-const InstructionRow = imports.instructionRow;
-const Transit = imports.transit;
-const TransitRouteLabel = imports.transitRouteLabel;
-const TransitStopRow = imports.transitStopRow;
-const Utils = imports.utils;
+import {InstructionRow} from './instructionRow.js';
+import * as Transit from './transit.js';
+import {TransitRouteLabel} from './transitRouteLabel.js';
+import {TransitStopRow} from './transitStopRow.js';
+import * as Utils from './utils.js';
 
-var TransitLegRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/transit-leg-row.ui',
-    InternalChildren: ['modeImage',
-                       'fromLabel',
-                       'routeGrid',
-                       'timeLabel',
-                       'footerStack',
-                       'expandButton',
-                       'detailsRevealer',
-                       'agencyLabel',
-                       'collapsButton',
-                       'instructionList',
-                       'eventBox']
-}, class TransitLegRow extends Gtk.ListBoxRow {
+const _ = gettext.gettext;
+
+export class TransitLegRow extends Gtk.ListBoxRow {
 
-    _init(params) {
-        this._leg = params.leg;
+    constructor(params) {
+        let leg = params.leg;
         delete params.leg;
 
-        this._start = params.start;
+        let start = params.start;
         delete params.start;
 
-        this._mapView = params.mapView;
+        let mapView = params.mapView;
         delete params.mapView;
 
-        super._init(params);
+        super(params);
 
+        this._leg = leg;
+        this._start = start;
+        this._mapView = mapView;
         this._modeImage.icon_name = this._leg.iconName;
         this._fromLabel.label = Transit.getFromLabel(this._leg, this._start);
 
         if (this._leg.transit) {
-            let routeLabel = new TransitRouteLabel.TransitRouteLabel({
-                                    leg: this._leg,
-                                 });
+            let routeLabel = new TransitRouteLabel({ leg: this._leg });
 
             this._routeGrid.attach(routeLabel, 0, 0, 1, 1);
 
@@ -183,10 +173,9 @@ var TransitLegRow = GObject.registerClass({
                 let stops = this._leg.intermediateStops;
                 for (let index = 0; index < stops.length; index++) {
                     let stop = stops[index];
-                    let row =
-                        new TransitStopRow.TransitStopRow({ visible: true,
-                                                            stop: stop,
-                                                            final: index === stops.length - 1 });
+                    let row = new TransitStopRow({ visible: true,
+                                                   stop: stop,
+                                                   final: index === stops.length - 1 });
                     this._instructionList.insert(row, -1);
                 }
             }
@@ -198,12 +187,26 @@ var TransitLegRow = GObject.registerClass({
                  index < this._leg.walkingInstructions.length - 1;
                  index++) {
                 let instruction = this._leg.walkingInstructions[index];
-                let row =
-                    new InstructionRow.InstructionRow({ visible: true,
-                                                        turnPoint: instruction });
+                let row = new InstructionRow({ visible: true,
+                                               turnPoint: instruction });
 
                 this._instructionList.insert(row, -1);
             }
         }
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/transit-leg-row.ui',
+    InternalChildren: ['modeImage',
+                       'fromLabel',
+                       'routeGrid',
+                       'timeLabel',
+                       'footerStack',
+                       'expandButton',
+                       'detailsRevealer',
+                       'agencyLabel',
+                       'collapsButton',
+                       'instructionList',
+                       'eventBox']
+}, TransitLegRow);
diff --git a/src/transitMoreRow.js b/src/transitMoreRow.js
index 64228b19..7b573d6e 100644
--- a/src/transitMoreRow.js
+++ b/src/transitMoreRow.js
@@ -19,21 +19,19 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Application = imports.application;
+import {Application} from './application.js';
 
-var TransitMoreRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/transit-more-row.ui',
-    InternalChildren: ['stack',
-                       'label']
-}, class TransitMoreRow extends Gtk.ListBoxRow {
+const _ = gettext.gettext;
+
+export class TransitMoreRow extends Gtk.ListBoxRow {
 
-    _init(params) {
-        super._init(params);
+    constructor(params) {
+        super(params);
 
         if (Application.routeQuery.arriveBy)
             this._label.label = _("Load earlier alternatives");
@@ -55,4 +53,10 @@ var TransitMoreRow = GObject.registerClass({
         else
             this._label.label = _("No later alternatives found.");
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/transit-more-row.ui',
+    InternalChildren: ['stack',
+                       'label']
+}, TransitMoreRow);
diff --git a/src/transitOptions.js b/src/transitOptions.js
index 0a964eef..12e6067c 100644
--- a/src/transitOptions.js
+++ b/src/transitOptions.js
@@ -19,7 +19,7 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-var TransitOptions = class TransitOptions {
+export class TransitOptions {
 
     constructor() {
         this._showAllTransitTypes = true;
@@ -48,23 +48,23 @@ var TransitOptions = class TransitOptions {
     get transitTypes() {
         return this._transitTypes;
     }
-};
 
-/* return true if the passed in options objects are equal, either both
- * accept any transit type, or both contains the same set of types, otherwise
- * return false
- */
-function equals(first, second) {
-    if (first.showAllTransitTypes && second.showAllTransitTypes) {
-        return true;
-    } else if (first.transitTypes.length !== second.transitTypes.length) {
-        return false;
-    } else {
-        for (let type of first.transitTypes) {
-            if (second.transitTypes.indexOf(type) === -1)
-                return false;
-        }
+    /* return true if the passed in options objects are equal, either both
+     * accept any transit type, or both contains the same set of types, otherwise
+     * return false
+     */
+    static equals(first, second) {
+        if (first.showAllTransitTypes && second.showAllTransitTypes) {
+            return true;
+        } else if (first.transitTypes.length !== second.transitTypes.length) {
+            return false;
+        } else {
+            for (let type of first.transitTypes) {
+                if (second.transitTypes.indexOf(type) === -1)
+                    return false;
+            }
 
-        return true;
+            return true;
+        }
     }
 }
diff --git a/src/transitOptionsPanel.js b/src/transitOptionsPanel.js
index 70e1a57e..ee2abaa2 100644
--- a/src/transitOptionsPanel.js
+++ b/src/transitOptionsPanel.js
@@ -19,16 +19,16 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Application = imports.application;
-const HVT = imports.hvt;
-const Time = imports.time;
-const TransitOptions = imports.transitOptions;
-const TransitPlan = imports.transitPlan;
+import {Application} from './application.js';
+import * as HVT from './hvt.js';
+import * as Time from './time.js';
+import {TransitOptions} from './transitOptions.js';
+import * as TransitPlan from './transitPlan.js';
 
 // in org.gnome.desktop.interface
 const CLOCK_FORMAT_KEY = 'clock-format';
@@ -40,24 +40,11 @@ const _timeFormat = new Intl.DateTimeFormat([], { hour:     '2-digit',
                                                   minute:   '2-digit',
                                                   hour12:   clockFormat === '12h' });
 
-var TransitOptionsPanel = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/transit-options-panel.ui',
-    InternalChildren: ['transitTimeOptionsComboBox',
-                       'transitTimeEntry',
-                       'transitDateButton',
-                       'transitDateCalendar',
-                       'transitParametersMenuButton',
-                       'busCheckButton',
-                       'tramCheckButton',
-                       'trainCheckButton',
-                       'subwayCheckButton',
-                       'ferryCheckButton',
-                       'airplaneCheckButton']
-}, class TransitOptionsPanel extends Gtk.Grid {
+export class TransitOptionsPanel extends Gtk.Grid {
 
-    _init(params) {
+    constructor(params) {
+        super(params);
         this._query = Application.routeQuery;
-        super._init(params);
         this._initTransitOptions();
     }
 
@@ -68,7 +55,7 @@ var TransitOptionsPanel = GObject.registerClass({
         this._transitTimeOptionsComboBox.active_id = 'leaveNow';
         this._timeSelected = false;
         this._dateSelected = false;
-        this._lastOptions = new TransitOptions.TransitOptions();
+        this._lastOptions = new TransitOptions();
     }
 
     _initTransitOptions() {
@@ -172,7 +159,7 @@ var TransitOptionsPanel = GObject.registerClass({
     }
 
     _createTransitOptions() {
-        let options = new TransitOptions.TransitOptions();
+        let options = new TransitOptions();
         let busSelected = this._busCheckButton.active;
         let tramSelected = this._tramCheckButton.active;
         let trainSelected = this._trainCheckButton.active;
@@ -211,4 +198,19 @@ var TransitOptionsPanel = GObject.registerClass({
             }
         }
     }
- });
+ }
+
+ GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/transit-options-panel.ui',
+    InternalChildren: ['transitTimeOptionsComboBox',
+                       'transitTimeEntry',
+                       'transitDateButton',
+                       'transitDateCalendar',
+                       'transitParametersMenuButton',
+                       'busCheckButton',
+                       'tramCheckButton',
+                       'trainCheckButton',
+                       'subwayCheckButton',
+                       'ferryCheckButton',
+                       'airplaneCheckButton']
+}, TransitOptionsPanel);
diff --git a/src/transitPlan.js b/src/transitPlan.js
index 8b037bb9..14d5c7de 100644
--- a/src/transitPlan.js
+++ b/src/transitPlan.js
@@ -19,22 +19,24 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
-const ngettext = imports.gettext.ngettext;
+import gettext from 'gettext';
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
 
-const BoundingBox = imports.boundingBox;
-const HVT = imports.hvt;
-const Time = imports.time;
-const Utils = imports.utils;
+import {BoundingBox} from './boundingBox.js';
+import * as HVT from './hvt.js';
+import * as Time from './time.js';
+import * as Utils from './utils.js';
+
+const _ = gettext.gettext;
+const ngettext = gettext.ngettext;
 
 /*
  * These constants corresponds to the routeType attribute of transit legs
  * in original GTFS specification.
  */
-var RouteType = {
+export const RouteType = {
     NON_TRANSIT: -1,
     TRAM:        0,
     SUBWAY:      1,
@@ -68,22 +70,13 @@ var RouteType = {
 /* extra time to add to the first itinerary leg when it's a walking leg */
 const WALK_SLACK = 120;
 
-var DEFAULT_ROUTE_COLOR = '4c4c4c';
-var DEFAULT_ROUTE_TEXT_COLOR = 'ffffff';
+export const DEFAULT_ROUTE_COLOR = '4c4c4c';
+export const DEFAULT_ROUTE_TEXT_COLOR = 'ffffff';
 
-var Plan = GObject.registerClass({
-    Signals: {
-        'update': {},
-        'reset': {},
-        'no-more-results': {},
-        'itinerary-selected': { param_types: [GObject.TYPE_OBJECT] },
-        'itinerary-deselected': {},
-        'error': { param_types: [GObject.TYPE_STRING] }
-    }
-}, class Plan extends GObject.Object {
+export class Plan extends GObject.Object {
 
-    _init(params) {
-        super._init(params);
+    constructor(params) {
+        super(params);
         this.reset();
         this._attribution = null;
         this._attributionUrl = null;
@@ -186,35 +179,35 @@ var Plan = GObject.registerClass({
     }
 
     _createBBox() {
-        let bbox = new BoundingBox.BoundingBox();
+        let bbox = new BoundingBox();
         this._itineraries.forEach(function(itinerary) {
             bbox.compose(itinerary.bbox);
         });
         return bbox;
     }
-});
+}
+
+GObject.registerClass({
+    Signals: {
+        'update': {},
+        'reset': {},
+        'no-more-results': {},
+        'itinerary-selected': { param_types: [GObject.TYPE_OBJECT] },
+        'itinerary-deselected': {},
+        'error': { param_types: [GObject.TYPE_STRING] }
+    }
+}, Plan);
 
-var Itinerary = GObject.registerClass(
-class Itinerary extends GObject.Object {
+export class Itinerary extends GObject.Object {
 
-    _init(params) {
-        this._duration = params.duration;
-        delete params.duration;
+    constructor(params) {
+        super();
 
+        this._duration = params.duration;
         this._departure = params.departure;
-        delete params.departure;
-
         this._arrival = params.arrival;
-        delete params.arrival;
-
         this._transfers = params.transfers;
-        delete params.transfers;
-
         this._legs = params.legs;
-        delete params.legs;
-
-        super._init(params);
-
         this.bbox = this._createBBox();
     }
 
@@ -284,7 +277,7 @@ class Itinerary extends GObject.Object {
     }
 
     _createBBox() {
-        let bbox = new BoundingBox.BoundingBox();
+        let bbox = new BoundingBox();
 
         this._legs.forEach(function(leg) {
             bbox.compose(leg.bbox);
@@ -405,76 +398,35 @@ class Itinerary extends GObject.Object {
     get isWalkingOnly() {
         return this.legs.length === 1 && !this.legs[0].isTransit;
     }
-});
+}
+
+GObject.registerClass(Itinerary);
 
-var Leg = class Leg {
+export class Leg {
 
     constructor(params) {
         this._route = params.route;
-        delete params.route;
-
         this._routeType = params.routeType;
-        delete params.routeType;
-
         this._departure = params.departure;
-        delete params.departure;
-
         this._arrival = params.arrival;
-        delete params.arrival;
-
         this._polyline = params.polyline;
-        delete params.polyline;
-
         this._fromCoordinate = params.fromCoordinate;
-        delete params.fromCoordinate;
-
         this._toCoordinate = params.toCoordinate;
-        delete params.toCoordinate;
-
         this._from = params.from;
-        delete params.from;
-
         this._to = params.to;
-        delete params.to;
-
         this._intermediateStops = params.intermediateStops;
-        delete params.intermediateStops;
-
         this._headsign = params.headsign;
-        delete params.headsign;
-
         this._isTransit = params.isTransit;
-        delete params.isTransit;
-
         this._walkingInstructions = params.walkingInstructions;
-        delete params.walkingInstructions;
-
         this._distance = params.distance;
-        delete params.distance;
-
         this._duration = params.duration;
-        delete params.duration;
-
         this._agencyName = params.agencyName;
-        delete params.agencyName;
-
         this._agencyUrl = params.agencyUrl;
-        delete params.agencyUrl;
-
         this._agencyTimezoneOffset = params.agencyTimezoneOffset;
-        delete params.agencyTimezoneOffset;
-
         this._color = params.color;
-        delete params.color;
-
         this._textColor = params.textColor;
-        delete params.textColor;
-
         this._tripShortName = params.tripShortName;
-        delete params.tripShortName;
-
         this.bbox = this._createBBox();
-
         this._compactRoute = null;
     }
 
@@ -638,7 +590,7 @@ var Leg = class Leg {
     }
 
     _createBBox() {
-        let bbox = new BoundingBox.BoundingBox();
+        let bbox = new BoundingBox();
 
         this.polyline.forEach(function({ latitude, longitude }) {
             bbox.extend(latitude, longitude);
@@ -761,25 +713,16 @@ var Leg = class Leg {
         return Time.formatTimeWithTZOffset(this.arrival,
                                            this.agencyTimezoneOffset);
     }
-};
+}
 
-var Stop = class Stop {
+export class Stop {
 
     constructor(params) {
         this._name = params.name;
-        delete params.name;
-
         this._arrival = params.arrival;
-        delete params.arrival;
-
         this._departure = params.departure;
-        delete params.departure;
-
         this._agencyTimezoneOffset = params.agencyTimezoneOffset;
-        delete params.agencyTimezoneOffset;
-
         this._coordinate = params.coordinate;
-        delete params.coordinate;
     }
 
     get name() {
@@ -805,7 +748,7 @@ var Stop = class Stop {
                                                this._agencyTimezoneOffset);
         }
     }
-};
+}
 
 function sortItinerariesByDepartureAsc(first, second) {
     /* always sort walk-only itineraries first, as they would always be
diff --git a/src/transitPrintLayout.js b/src/transitPrintLayout.js
index aada2fe0..1339b62e 100644
--- a/src/transitPrintLayout.js
+++ b/src/transitPrintLayout.js
@@ -19,20 +19,20 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Cairo = imports.cairo;
-const Champlain = imports.gi.Champlain;
-const Clutter = imports.gi.Clutter;
-const GObject = imports.gi.GObject;
-const Pango = imports.gi.Pango;
-
-const Color = imports.color;
-const Gfx = imports.gfx;
-const MapSource = imports.mapSource;
-const PrintLayout = imports.printLayout;
-const Transit = imports.transit;
-const TransitArrivalMarker = imports.transitArrivalMarker;
-const TransitBoardMarker = imports.transitBoardMarker;
-const TransitWalkMarker = imports.transitWalkMarker;
+import Cairo from 'cairo';
+import Champlain from 'gi://Champlain';
+import Clutter from 'gi://Clutter';
+import GObject from 'gi://GObject';
+import Pango from 'gi://Pango';
+
+import * as Color from './color.js';
+import * as Gfx from './gfx.js';
+import * as MapSource from './mapSource.js';
+import {PrintLayout} from './printLayout.js';
+import * as Transit from './transit.js';
+import {TransitArrivalMarker} from './transitArrivalMarker.js';
+import {TransitBoardMarker} from './transitBoardMarker.js';
+import {TransitWalkMarker} from './transitWalkMarker.js';
 
 // stroke color for walking paths
 const _STROKE_COLOR = new Clutter.Color({ red: 0,
@@ -62,16 +62,17 @@ const _Instruction = {
 // luminance threashhold for drawing outline around route label badges
 const OUTLINE_LUMINANCE_THREASHHOLD = 0.9;
 
-var TransitPrintLayout = GObject.registerClass(
-class TransitPrintLayout extends PrintLayout.PrintLayout {
+export class TransitPrintLayout extends PrintLayout {
 
-    _init(params) {
-        this._itinerary = params.itinerary;
+    constructor(params) {
+        let itinerary = params.itinerary;
         delete params.itinerary;
 
         params.totalSurfaces = this._getNumberOfSurfaces();
 
-        super._init(params);
+        super(params);
+
+        this._itinerary = itinerary;
     }
 
     _getNumberOfSurfaces() {
@@ -149,16 +150,15 @@ class TransitPrintLayout extends PrintLayout.PrintLayout {
     }
 
     _createStartMarker(leg, previousLeg) {
-        return new TransitWalkMarker.TransitWalkMarker({ leg: leg,
-                                                         previousLeg: previousLeg });
+        return new TransitWalkMarker({ leg: leg, previousLeg: previousLeg });
     }
 
     _createBoardMarker(leg) {
-        return new TransitBoardMarker.TransitBoardMarker({ leg: leg });
+        return new TransitBoardMarker({ leg: leg });
     }
 
     _createArrivalMarker(leg) {
-        return new TransitArrivalMarker.TransitArrivalMarker({ leg: leg });
+        return new TransitArrivalMarker({ leg: leg });
     }
 
     _addRouteLayer(view, index) {
@@ -335,4 +335,6 @@ class TransitPrintLayout extends PrintLayout.PrintLayout {
 
         this._drawArrival(instructionWidth, instructionHeight);
     }
-});
+}
+
+GObject.registerClass(TransitPrintLayout);
diff --git a/src/transitRouteLabel.js b/src/transitRouteLabel.js
index 8e1f0388..b8eebe2d 100644
--- a/src/transitRouteLabel.js
+++ b/src/transitRouteLabel.js
@@ -19,14 +19,14 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Cairo = imports.cairo;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Cairo from 'cairo';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Color = imports.color;
-const Gfx = imports.gfx;
-const Utils = imports.utils;
+import * as Color from './color.js';
+import * as Gfx from './gfx.js';
+import * as Utils from './utils.js';
 
 /* threashhold for route color luminance when we consider it more or less
  * as white, and draw an outline around the label
@@ -41,17 +41,15 @@ const DARK_OUTLINE_LUMINANCE_THREASHHOLD = 0.1;
 const HIGH_CONTRAST_COLOR = '000000';
 const HIGH_CONTRAST_TEXT_COLOR = 'ffffff';
 
-var TransitRouteLabel = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/transit-route-label.ui',
-}, class TransitRouteLabel extends Gtk.Label {
+export class TransitRouteLabel extends Gtk.Label {
 
-    _init(params) {
+    constructor(params) {
         let leg = params.leg;
         let compact = params.compact;
 
         delete params.leg;
         delete params.compact;
-        super._init(params);
+        super(params);
 
         this._setLabel(leg, compact);
         this.connect('draw', this._onDraw.bind(this));
@@ -121,4 +119,8 @@ var TransitRouteLabel = GObject.registerClass({
 
         return false;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/transit-route-label.ui',
+}, TransitRouteLabel);
diff --git a/src/transitRouter.js b/src/transitRouter.js
index 0f3892bd..8eb1563d 100644
--- a/src/transitRouter.js
+++ b/src/transitRouter.js
@@ -19,12 +19,19 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GLib = imports.gi.GLib;
+import GLib from 'gi://GLib';
+
+import {BoundingBox} from './boundingBox.js';
+import * as Service from './service.js';
+import {Plan} from './transitPlan.js';
+import * as Utils from './utils.js';
+
+// plugins
+import {GoMetro} from './transitplugins/goMetro.js';
+import {OpendataCH} from './transitplugins/opendataCH.js';
+import {OpenTripPlanner} from './transitplugins/openTripPlanner.js';
+import {Resrobot} from './transitplugins/resrobot.js';
 
-const BoundingBox = imports.boundingBox;
-const Service = imports.service;
-const TransitPlan = imports.transitPlan;
-const Utils = imports.utils;
 
 /**
  * Class responsible for delegating requests to perform routing in transit
@@ -32,14 +39,13 @@ const Utils = imports.utils;
  * Holds the the shared plan instance (filled with journeys on successful
  * requests).
  */
-var TransitRouter = class TransitRoute {
+export class TransitRouter {
     constructor(params) {
-        this._plan = new TransitPlan.Plan();
+        this._plan = new Plan();
         this._query = params.query;
         this._providers = Service.getService().transitProviders;
         this._providerCache = [];
         this._language = Utils.getLanguage();
-        this._probePlugins();
     }
 
     get enabled() {
@@ -60,13 +66,12 @@ var TransitRouter = class TransitRoute {
         if (pluginOverride) {
             // override plugin was specified, try instanciating if not done yet
             if (!this._currPluginInstance) {
-                let module = this._availablePlugins[pluginOverride];
-
-                if (module) {
-                    this._currPluginInstance =
-                        new imports.transitplugins[module][pluginOverride]();
-                } else {
-                    throw new Error('Specified override plugin not found');
+                try {
+                    this._currentPluginInstance =
+                        eval(`new ${pluginOverride}()`);
+                } catch (e) {
+                    Utils.debug('Unable to instanciate plugin: ' + pluginOverride);
+                    throw e;
                 }
             }
         } else {
@@ -103,16 +108,6 @@ var TransitRouter = class TransitRoute {
             throw new Error('No previous provider');
     }
 
-    _probePlugins() {
-        this._availablePlugins = [];
-
-        for (let module in imports.transitplugins) {
-            for (let pluginClass in imports.transitplugins[module]) {
-                this._availablePlugins[pluginClass] = module;
-            }
-        }
-    }
-
     /**
      * Get attribution for a provider. Returns a language-specific
      * 'attribution:<lang>' tag if available, otherwise 'attribution'
@@ -170,10 +165,10 @@ var TransitRouter = class TransitRoute {
                     }
 
                     let [x1, y1, x2, y2] = bbox;
-                    let cbbox = new BoundingBox.BoundingBox({ bottom: x1,
-                                                              left: y1,
-                                                              top: x2,
-                                                              right: y2 });
+                    let cbbox = new BoundingBox({ bottom: x1,
+                                                  left: y1,
+                                                  top: x2,
+                                                  right: y2 });
 
                     if (cbbox.covers(location.latitude,
                                      location.longitude)) {
@@ -233,24 +228,18 @@ var TransitRouter = class TransitRoute {
             if (this._providerCache[provider.name])
                 return [provider, this._providerCache[provider.name]];
 
-            let module = this._availablePlugins[plugin];
+            try {
+                let params = provider.params;
+                let instance =
+                    params ? eval(`new ${plugin}(params)`):
+                             eval(`new ${plugin}()`);
 
-            if (module) {
-                try {
-                    let params = provider.params;
-                    let instance =
-                        params ? new imports.transitplugins[module][plugin](params) :
-                                 new imports.transitplugins[module][plugin]();
+                this._providerCache[provider.name] = instance;
 
-                    this._providerCache[provider.name] = instance;
-
-                    return [provider, instance];
-                } catch (e) {
-                    Utils.debug('Failed to instantiate transit plugin: ' +
-                                plugin + ": " + e);
-                }
-            } else {
-                Utils.debug('Transit provider plugin not available: ' + plugin);
+                return [provider, instance];
+            } catch (e) {
+                Utils.debug('Failed to instantiate transit plugin: ' +
+                            plugin + ": " + e);
             }
         }
 
diff --git a/src/transitStopRow.js b/src/transitStopRow.js
index f3cbe790..c607d963 100644
--- a/src/transitStopRow.js
+++ b/src/transitStopRow.js
@@ -19,27 +19,32 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-var TransitStopRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/transit-stop-row.ui',
-    InternalChildren: [ 'nameLabel',
-                        'timeLabel' ]
-}, class TransitStopRow extends Gtk.ListBoxRow {
+const _ = gettext.gettext;
+
+export class TransitStopRow extends Gtk.ListBoxRow {
 
-    _init(params) {
-        this.stop = params.stop;
+    constructor(params) {
+        let stop = params.stop;
         delete params.stop;
 
-        this._final = params.final;
+        let final = params.final;
         delete params.final;
 
-        super._init(params);
+        super(params);
 
+        this.stop = stop;
         this._nameLabel.label = this.stop.name;
-        this._timeLabel.label = this.stop.prettyPrint({ isFinal: this._final });
+        this._timeLabel.label = this.stop.prettyPrint({ isFinal: final });
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/transit-stop-row.ui',
+    InternalChildren: [ 'nameLabel',
+                        'timeLabel' ]
+}, TransitStopRow);
diff --git a/src/transitWalkMarker.js b/src/transitWalkMarker.js
index 60f72f57..c1221391 100644
--- a/src/transitWalkMarker.js
+++ b/src/transitWalkMarker.js
@@ -19,18 +19,17 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
 
-const Color = imports.color;
-const Location = imports.location;
-const MapMarker = imports.mapMarker;
-const Place = imports.place;
+import * as Color from './color.js';
+import {Location} from './location.js';
+import {MapMarker} from './mapMarker.js';
+import {Place} from './place.js';
 
-var TransitWalkMarker = GObject.registerClass(
-class TransitWalkMarker extends MapMarker.MapMarker {
+export class TransitWalkMarker extends MapMarker {
 
-    _init(params) {
+    constructor(params) {
         /* if there is a preceding leg, put the marker at the end of that leg
          * to avoid gaps, since we will "fill out" the walking leg path line
          * since sometimes the walking route might not reach exactly to the
@@ -48,13 +47,12 @@ class TransitWalkMarker extends MapMarker.MapMarker {
         delete params.leg;
         delete params.previousLeg;
 
-        let location = new Location.Location({ latitude: point.latitude,
-                                               longitude: point.longitude
-                                             });
+        let location = new Location({ latitude: point.latitude,
+                                      longitude: point.longitude });
 
-        params.place = new Place.Place({ location: location });
+        params.place = new Place({ location: location });
 
-        super._init(params);
+        super(params);
 
         let bgRed = Color.parseColor(bgColor, 0);
         let bgGreen = Color.parseColor(bgColor, 1);
@@ -74,4 +72,6 @@ class TransitWalkMarker extends MapMarker.MapMarker {
         return { x: Math.floor(this.width / 2) - 1,
                  y: Math.floor(this.height / 2) - 1 };
     }
-});
+}
+
+GObject.registerClass(TransitWalkMarker);
diff --git a/src/transitplugins/goMetro.js b/src/transitplugins/goMetro.js
index e68cd1c2..2c459d09 100644
--- a/src/transitplugins/goMetro.js
+++ b/src/transitplugins/goMetro.js
@@ -25,23 +25,24 @@
  * https://proserver.gometro.co.za/api/v1/docs/#multimodal-routing
  */
 
-const BASE_URL = 'https://proserver.gometro.co.za/api';
-const API_VERSION = 'v1';
+import gettext from 'gettext';
 
-const NATIVE_TIMEZONE = 'Africa/Cape_Town';
+import GLib from 'gi://GLib';
 
-const _ = imports.gettext.gettext;
+import * as HVT from '../hvt.js';
+import {RouteType} from '../transitPlan.js';
+import * as Utils from '../utils.js';
 
-const GLib = imports.gi.GLib;
+import {OpenTripPlanner} from './openTripPlanner.js';
 
-const Application = imports.application;
-const HVT = imports.hvt;
-const TransitPlan = imports.transitPlan;
-const Utils = imports.utils;
+const _ = gettext.gettext;
 
-const OpenTripPlanner = imports.transitplugins.openTripPlanner;
+const BASE_URL = 'https://proserver.gometro.co.za/api';
+const API_VERSION = 'v1';
+
+const NATIVE_TIMEZONE = 'Africa/Cape_Town';
 
-var GoMetro = class GoMetro extends OpenTripPlanner.OpenTripPlanner {
+export class GoMetro extends OpenTripPlanner {
     constructor() {
         super({ baseUrl: BASE_URL });
 
@@ -101,7 +102,7 @@ var GoMetro = class GoMetro extends OpenTripPlanner.OpenTripPlanner {
     _createLeg(leg, index, legs) {
         let result = super._createLeg(leg, index, legs);
 
-        if (result.routeType === TransitPlan.RouteType.FERRY)
+        if (result.routeType === RouteType.FERRY)
             result.routeType = HVT.TAXI_SERVICE;
 
         return result;
@@ -112,16 +113,16 @@ var GoMetro = class GoMetro extends OpenTripPlanner.OpenTripPlanner {
         let transitOptions = this._query.transitOptions;
 
         if (transitOptions.showAllTransitTypes ||
-            transitOptions.transitTypes.includes(TransitPlan.RouteType.TRAIN))
+            transitOptions.transitTypes.includes(RouteType.TRAIN))
             params += 'RAIL,';
         if (transitOptions.showAllTransitTypes ||
-            transitOptions.transitTypes.includes(TransitPlan.RouteType.BUS))
+            transitOptions.transitTypes.includes(RouteType.BUS))
             params += 'BUS,';
         if (transitOptions.showAllTransitTypes ||
-            transitOptions.transitTypes.includes(TransitPlan.RouteType.FERRY))
+            transitOptions.transitTypes.includes(RouteType.FERRY))
             params += 'FERRY,';
         if (transitOptions.showAllTransitTypes ||
-            transitOptions.transitTypes.includes(TransitPlan.RouteType.TRAM))
+            transitOptions.transitTypes.includes(RouteType.TRAM))
             params += 'TRAM,';
         if (transitOptions.showAllTransitTypes)
             params += 'GONDOLA,';
diff --git a/src/transitplugins/openTripPlanner.js b/src/transitplugins/openTripPlanner.js
index 70c6a74a..9c80e910 100644
--- a/src/transitplugins/openTripPlanner.js
+++ b/src/transitplugins/openTripPlanner.js
@@ -19,24 +19,26 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
-
-const Champlain = imports.gi.Champlain;
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
-
-const Application = imports.application;
-const EPAF = imports.epaf;
-const GraphHopperTransit = imports.graphHopperTransit;
-const HTTP = imports.http;
-const HVT = imports.hvt;
-const Location = imports.location;
-const Place = imports.place;
-const Route = imports.route;
-const RouteQuery = imports.routeQuery;
-const Service = imports.service;
-const TransitPlan = imports.transitPlan;
-const Utils = imports.utils;
+import gettext from 'gettext';
+
+import Champlain from 'gi://Champlain';
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
+
+import {Application} from '../application.js';
+import * as EPAF from '../epaf.js';
+import * as GraphHopperTransit from '../graphHopperTransit.js';
+import {Query} from '../http.js';
+import * as HVT from '../hvt.js';
+import {Location} from '../location.js';
+import {Place} from '../place.js';
+import {TurnPoint} from '../route.js';
+import {RouteQuery} from '../routeQuery.js';
+import * as Service from '../service.js';
+import {Itinerary, Leg, RouteType, Stop} from '../transitPlan.js';
+import * as Utils from '../utils.js';
+
+const _ = gettext.gettext;
 
 /**
  * This module implements the interface for communicating with an OpenTripPlanner
@@ -110,7 +112,7 @@ const NUM_STOPS_TO_TRY = 5;
 // gap to use when fetching additional routes
 const GAP_BEFORE_MORE_RESULTS = 120;
 
-var OpenTripPlanner = class OpenTripPlanner {
+export class OpenTripPlanner {
 
     constructor(params) {
         let onlyTransitDataEnv = GLib.getenv('OTP_ONLY_TRANSIT_DATA');
@@ -160,15 +162,15 @@ var OpenTripPlanner = class OpenTripPlanner {
 
     _getMode(routeType) {
         switch (routeType) {
-        case TransitPlan.RouteType.TRAM:
+        case RouteType.TRAM:
             return 'TRAM';
-        case TransitPlan.RouteType.TRAIN:
+        case RouteType.TRAIN:
             return 'RAIL';
-        case TransitPlan.RouteType.SUBWAY:
+        case RouteType.SUBWAY:
             return 'SUBWAY';
-        case TransitPlan.RouteType.BUS:
+        case RouteType.BUS:
             return 'BUS';
-        case TransitPlan.RouteType.FERRY:
+        case RouteType.FERRY:
             return 'FERRY';
         case HVT.AIR_SERVICE:
             return 'AIRPLANE';
@@ -248,7 +250,7 @@ var OpenTripPlanner = class OpenTripPlanner {
     }
 
     _fetchRoutesForStop(stop, callback) {
-        let query = new HTTP.Query();
+        let query = new Query();
         let uri = new Soup.URI(this._getRouterUrl() + '/index/stops/' +
                                stop.id + '/routes');
         let request = new Soup.Message({ method: 'GET', uri: uri });
@@ -273,16 +275,16 @@ var OpenTripPlanner = class OpenTripPlanner {
         for (let i = 0; i < desiredTransitTypes.length; i++) {
             let type = desiredTransitTypes[i];
 
-            if (type === TransitPlan.RouteType.TRAM && route.mode === 'TRAM')
+            if (type === RouteType.TRAM && route.mode === 'TRAM')
                 return true;
-            else if (type === TransitPlan.RouteType.SUBWAY && route.mode === 'SUBWAY')
+            else if (type === RouteType.SUBWAY && route.mode === 'SUBWAY')
                 return true;
-            else if (type === TransitPlan.RouteType.TRAIN && route.mode === 'RAIL')
+            else if (type === RouteType.TRAIN && route.mode === 'RAIL')
                 return true;
-            else if (type === TransitPlan.RouteType.BUS &&
+            else if (type === RouteType.BUS &&
                      (route.mode === 'BUS' || route.mode === 'TAXI'))
                 return true;
-            else if (type === TransitPlan.RouteType.FERRY && route.mode === 'FERRY')
+            else if (type === RouteType.FERRY && route.mode === 'FERRY')
                 return true;
         }
 
@@ -322,7 +324,7 @@ var OpenTripPlanner = class OpenTripPlanner {
             let params = { lat: point.place.location.latitude,
                            lon: point.place.location.longitude,
                            radius: STOP_SEARCH_RADIUS };
-            let query = new HTTP.Query(params);
+            let query = new Query(params);
             let uri = new Soup.URI(this._getRouterUrl() +
                                    '/index/stops?' + query.toString());
             let request = new Soup.Message({ method: 'GET', uri: uri });
@@ -518,7 +520,7 @@ var OpenTripPlanner = class OpenTripPlanner {
     }
 
     _getPlanUrlFromParams(params) {
-        let query = new HTTP.Query(params);
+        let query = new Query(params);
 
         return this._getRouterUrl() + '/plan?' + query.toString();
     }
@@ -724,7 +726,7 @@ var OpenTripPlanner = class OpenTripPlanner {
                                                               to.place.name,
                                                               route);
                 let newItinerary =
-                    new TransitPlan.Itinerary({departure: itinerary.departure,
+                    new Itinerary({departure: itinerary.departure,
                                                duration: route.time / 1000,
                                                legs: [leg]});
                 callback(newItinerary);
@@ -1006,11 +1008,11 @@ var OpenTripPlanner = class OpenTripPlanner {
 
     _createItinerary(itinerary) {
         let legs = this._createLegs(itinerary.legs);
-        return new TransitPlan.Itinerary({ duration:  itinerary.duration,
-                                           transfers: itinerary.transfers,
-                                           departure: itinerary.startTime,
-                                           arrival:   itinerary.endTime,
-                                           legs:      legs});
+        return new Itinerary({ duration:  itinerary.duration,
+                               transfers: itinerary.transfers,
+                               departure: itinerary.startTime,
+                               arrival:   itinerary.endTime,
+                               legs:      legs});
     }
 
     _createLegs(legs) {
@@ -1048,27 +1050,27 @@ var OpenTripPlanner = class OpenTripPlanner {
             last && !leg.transitLeg ? this._query.filledPoints.last().place.name :
                                       leg.to.name;
 
-        let result = new TransitPlan.Leg({ departure:            leg.from.departure,
-                                           arrival:              leg.to.arrival,
-                                           from:                 from,
-                                           to:                   to,
-                                           headsign:             leg.headsign,
-                                           fromCoordinate:       [leg.from.lat,
-                                                                  leg.from.lon],
-                                           toCoordinate:         [leg.to.lat,
-                                                                  leg.to.lon],
-                                           route:                leg.route,
-                                           routeType:            leg.routeType,
-                                           polyline:             polyline,
-                                           isTransit:            leg.transitLeg,
-                                           distance:             leg.distance,
-                                           duration:             leg.duration,
-                                           agencyName:           leg.agencyName,
-                                           agencyUrl:            leg.agencyUrl,
-                                           agencyTimezoneOffset: leg.agencyTimeZoneOffset,
-                                           color:                color,
-                                           textColor:            textColor,
-                                           tripShortName:        leg.tripShortName });
+        let result = new Leg({ departure:            leg.from.departure,
+                               arrival:              leg.to.arrival,
+                               from:                 from,
+                               to:                   to,
+                               headsign:             leg.headsign,
+                               fromCoordinate:       [leg.from.lat,
+                                                      leg.from.lon],
+                               toCoordinate:         [leg.to.lat,
+                                                      leg.to.lon],
+                               route:                leg.route,
+                               routeType:            leg.routeType,
+                               polyline:             polyline,
+                               isTransit:            leg.transitLeg,
+                               distance:             leg.distance,
+                               duration:             leg.duration,
+                               agencyName:           leg.agencyName,
+                               agencyUrl:            leg.agencyUrl,
+                               agencyTimezoneOffset: leg.agencyTimeZoneOffset,
+                               color:                color,
+                               textColor:            textColor,
+                               tripShortName:        leg.tripShortName });
 
         if (leg.transitLeg && leg.intermediateStops)
             result.intermediateStops = this._createIntermediateStops(leg);
@@ -1086,20 +1088,20 @@ var OpenTripPlanner = class OpenTripPlanner {
         /* instroduce an extra stop at the end (in additional to the
          * intermediate stops we get from OTP
          */
-        intermediateStops.push(new TransitPlan.Stop({ name: leg.to.name,
-                                                      arrival: leg.to.arrival,
-                                                      agencyTimezoneOffset: leg.agencyTimeZoneOffset,
-                                                      coordinate: [leg.to.lat,
-                                                                   leg.to.lon] }));
+        intermediateStops.push(new Stop({ name: leg.to.name,
+                                          arrival: leg.to.arrival,
+                                          agencyTimezoneOffset: leg.agencyTimeZoneOffset,
+                                          coordinate: [leg.to.lat,
+                                                       leg.to.lon] }));
         return intermediateStops;
     }
 
     _createIntermediateStop(stop, leg) {
-        return new TransitPlan.Stop({ name:       stop.name,
-                                      arrival:    stop.arrival,
-                                      departure:  stop.departure,
-                                      agencyTimezoneOffset: leg.agencyTimeZoneOffset,
-                                      coordinate: [stop.lat, stop.lon] });
+        return new Stop({ name:       stop.name,
+                          arrival:    stop.arrival,
+                          departure:  stop.departure,
+                          agencyTimezoneOffset: leg.agencyTimeZoneOffset,
+                          coordinate: [stop.lat, stop.lon] });
     }
 
     /**
@@ -1109,9 +1111,9 @@ var OpenTripPlanner = class OpenTripPlanner {
     _createTurnpoints(leg, polyline) {
         if (leg.steps) {
             let steps = leg.steps;
-            let startPoint = new Route.TurnPoint({
+            let startPoint = new TurnPoint({
                 coordinate:  polyline[0],
-                type:        Route.TurnPointType.START,
+                type:        TurnPoint.Type.START,
                 distance:    0,
                 instruction: _("Start!"),
                 time:        0,
@@ -1122,9 +1124,9 @@ var OpenTripPlanner = class OpenTripPlanner {
                 turnpoints.push(this._createTurnpoint(step));
             });
 
-            let endPoint = new Route.TurnPoint({
+            let endPoint = new TurnPoint({
                 coordinate: polyline.last(),
-                type:       Route.TurnPoint.END,
+                type:       TurnPoint.Type.END,
                 distance:   0,
                 instruction:_("Arrive")
             });
@@ -1140,7 +1142,7 @@ var OpenTripPlanner = class OpenTripPlanner {
     _createTurnpoint(step) {
         let coordinate = new Champlain.Coordinate({ latitude: step.lat,
                                                     longitude: step.lon });
-        let turnpoint = new Route.TurnPoint({
+        let turnpoint = new TurnPoint({
             coordinate: coordinate,
             type: this._getTurnpointType(step),
             distance: step.distance,
@@ -1154,28 +1156,28 @@ var OpenTripPlanner = class OpenTripPlanner {
         switch (step.relativeDirection) {
             case 'DEPART':
             case 'CONTINUE':
-                return Route.TurnPointType.CONTINUE;
+                return TurnPoint.Type.CONTINUE;
             case 'LEFT':
-                return Route.TurnPointType.LEFT;
+                return TurnPoint.Type.LEFT;
             case 'SLIGHTLY_LEFT':
-                return Route.TurnPointType.SLIGHT_LEFT;
+                return TurnPoint.Type.SLIGHT_LEFT;
             case 'HARD_LEFT':
-                return Route.TurnPointType.SHARP_LEFT;
+                return TurnPoint.Type.SHARP_LEFT;
             case 'RIGHT':
-                return Route.TurnPointType.RIGHT;
+                return TurnPoint.Type.RIGHT;
             case 'SLIGHTLY_RIGHT':
-                return Route.TurnPointType.SLIGHT_RIGHT;
+                return TurnPoint.Type.SLIGHT_RIGHT;
             case 'HARD_RIGHT':
-                return Route.TurnPointType.SHARP_RIGHT;
+                return TurnPoint.Type.SHARP_RIGHT;
             case 'CIRCLE_CLOCKWISE':
             case 'CIRCLE_COUNTERCLOCKWISE':
-                return Route.TurnPointType.ROUNDABOUT;
+                return TurnPoint.Type.ROUNDABOUT;
             case 'ELEVATOR':
-                return Route.TurnPointType.ELEVATOR;
+                return TurnPoint.Type.ELEVATOR;
             case 'UTURN_LEFT':
-                return Route.TurnPointType.UTURN_LEFT;
+                return TurnPoint.Type.UTURN_LEFT;
             case 'UTURN_RIGHT':
-                return Route.TurnPointType.UTURN_RIGHT;
+                return TurnPoint.Type.UTURN_RIGHT;
             default:
                 return null;
         }
diff --git a/src/transitplugins/opendataCH.js b/src/transitplugins/opendataCH.js
index cd4640c1..e9431005 100644
--- a/src/transitplugins/opendataCH.js
+++ b/src/transitplugins/opendataCH.js
@@ -27,16 +27,16 @@
  * https://transport.opendata.ch/docs.html
  */
 
-const Champlain = imports.gi.Champlain;
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import Champlain from 'gi://Champlain';
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
-const Application = imports.application;
-const GraphHopperTransit = imports.graphHopperTransit;
-const HVT = imports.hvt;
-const HTTP = imports.http;
-const TransitPlan = imports.transitPlan;
-const Utils = imports.utils;
+import {Application} from '../application.js';
+import * as GraphHopperTransit from '../graphHopperTransit.js';
+import * as HVT from '../hvt.js';
+import {Query} from '../http.js';
+import {Itinerary, Leg, RouteType, Stop} from '../transitPlan.js';
+import * as Utils from '../utils.js';
 
 const BASE_URL = 'https://transport.opendata.ch';
 const API_VERSION = 'v1';
@@ -96,7 +96,7 @@ const Category = {
 // gap to use when fetching additional routes
 const GAP_BEFORE_MORE_RESULTS = 120;
 
-var OpendataCH = class OpendataCH {
+export class OpendataCH {
     constructor() {
         this._session = new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version });
         this._plan = Application.routingDelegator.transitRouter.plan;
@@ -143,8 +143,8 @@ var OpendataCH = class OpendataCH {
             this._fetchResults();
         } else {
             let location = points[index].place.location;
-            let query = new HTTP.Query({ x: location.latitude,
-                                         y: location.longitude });
+            let query = new Query({ x: location.latitude,
+                                    y: location.longitude });
             let uri = new Soup.URI(BASE_URL + '/' + API_VERSION + '/locations?' +
                                    query.toString());
             let request = new Soup.Message({ method: 'GET', uri: uri });
@@ -233,10 +233,10 @@ var OpendataCH = class OpendataCH {
         let [startTime,] = this._parseTime(from.departure);
         let [endTime,] = this._parseTime(to.arrival);
 
-        return new TransitPlan.Itinerary({ duration:  duration,
-                                           departure: startTime,
-                                           arrival:   endTime,
-                                           legs:      legs });
+        return new Itinerary({ duration:  duration,
+                               departure: startTime,
+                               arrival:   endTime,
+                               legs:      legs });
     }
 
     /**
@@ -294,23 +294,23 @@ var OpendataCH = class OpendataCH {
         let [departureX, departureY, arrivalX, arrivalY] =
             this._getCoordsForSection(section, index, sections);
 
-        let result = new TransitPlan.Leg({ departure:            departureTime,
-                                           arrival:              arrivalTime,
-                                           from:                 from,
-                                           to:                   to,
-                                           headsign:             headsign,
-                                           fromCoordinate:       [departureX,
-                                                                  departureY],
-                                           toCoordinate:         [arrivalX,
-                                                                  arrivalY],
-                                           route:                route,
-                                           routeType:            routeType,
-                                           polyline:             polyline,
-                                           isTransit:            isTransit,
-                                           duration:             duration,
-                                           agencyName:           agencyName,
-                                           agencyTimezoneOffset: tzOffset,
-                                           tripShortName:        route });
+        let result = new Leg({ departure:            departureTime,
+                               arrival:              arrivalTime,
+                               from:                 from,
+                               to:                   to,
+                               headsign:             headsign,
+                               fromCoordinate:       [departureX,
+                                                      departureY],
+                               toCoordinate:         [arrivalX,
+                                                      arrivalY],
+                               route:                route,
+                               routeType:            routeType,
+                               polyline:             polyline,
+                               isTransit:            isTransit,
+                               duration:             duration,
+                               agencyName:           agencyName,
+                               agencyTimezoneOffset: tzOffset,
+                               tripShortName:        route });
 
         if (journey)
             result.intermediateStops = this._createIntermediateStops(journey);
@@ -433,12 +433,12 @@ var OpendataCH = class OpendataCH {
         if (!departure)
             departure = arrival;
 
-        return new TransitPlan.Stop({ name:                 pass.station.name,
-                                      arrival:              arrival,
-                                      departure:            departure,
-                                      agencyTimezoneOffset: departureTzOffset || arrivalTzOffset,
-                                      coordinate: [pass.location.coordinate.x,
-                                                   pass.location.coordinate.y] });
+        return new Stop({ name:                 pass.station.name,
+                          arrival:              arrival,
+                          departure:            departure,
+                          agencyTimezoneOffset: departureTzOffset || arrivalTzOffset,
+                          coordinate: [pass.location.coordinate.x,
+                                       pass.location.coordinate.y] });
     }
 
     // get a time suitably formatted for the the query param
@@ -504,7 +504,7 @@ var OpendataCH = class OpendataCH {
                 params.date = this._query.date;
         }
 
-        let query = new HTTP.Query(params);
+        let query = new Query(params);
 
         if (this._viaLocations.length > 0) {
             this._viaLocations.forEach((p) => { query.add('via', p); });
@@ -528,13 +528,13 @@ var OpendataCH = class OpendataCH {
 
     _transportationForTransitType(type) {
         switch (type) {
-            case TransitPlan.RouteType.BUS:
+            case RouteType.BUS:
                 return Transportations.BUS;
-            case TransitPlan.RouteType.TRAM:
+            case RouteType.TRAM:
                 return Transportations.TRAM;
-            case TransitPlan.RouteType.TRAIN:
+            case RouteType.TRAIN:
                 return Transportations.TRAIN;
-            case TransitPlan.RouteType.FERRY:
+            case RouteType.FERRY:
                 return Transportations.SHIP;
             default:
                 return null;
diff --git a/src/transitplugins/resrobot.js b/src/transitplugins/resrobot.js
index d7c87e98..29a84a92 100644
--- a/src/transitplugins/resrobot.js
+++ b/src/transitplugins/resrobot.js
@@ -27,16 +27,16 @@
  * https://www.trafiklab.se/api/resrobot-reseplanerare/dokumentation/sokresa
  */
 
-const Champlain = imports.gi.Champlain;
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import Champlain from 'gi://Champlain';
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
-const Application = imports.application;
-const GraphHopperTransit = imports.graphHopperTransit;
-const HTTP = imports.http;
-const HVT = imports.hvt;
-const TransitPlan = imports.transitPlan;
-const Utils = imports.utils;
+import {Application} from '../application.js';
+import * as GraphHopperTransit from '../graphHopperTransit.js';
+import {Query} from '../http.js';
+import * as HVT from '../hvt.js';
+import {Itinerary, Leg, RouteType, Stop} from '../transitPlan.js';
+import * as Utils from '../utils.js';
 
 const BASE_URL = 'https://api.resrobot.se';
 const API_VERSION = 'v2.1';
@@ -88,7 +88,7 @@ const WALK_SEARCH_RADIUS = 2000;
 // maximum distance for walk-only journey
 const MAX_WALK_ONLY_DISTANCE = 2500;
 
-var Resrobot = class Resrobot {
+export class Resrobot {
     constructor(params) {
         this._session = new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version });
         this._plan = Application.routingDelegator.transitRouter.plan;
@@ -134,8 +134,8 @@ var Resrobot = class Resrobot {
     }
 
     _fetchNearbyStops(lat, lon, num, radius, callback) {
-        let query = new HTTP.Query(this._getNearbyStopsQueryParams(lat, lon,
-                                                                   num, radius));
+        let query = new Query(this._getNearbyStopsQueryParams(lat, lon,
+                                                              num, radius));
         let uri = new Soup.URI(BASE_URL + '/' + API_VERSION +
                                '/location.nearbystops?' + query.toString());
         let request = new Soup.Message({ method: 'GET', uri: uri });
@@ -170,7 +170,7 @@ var Resrobot = class Resrobot {
     }
 
     _fetchResults() {
-        let query = new HTTP.Query(this._getQueryParams());
+        let query = new Query(this._getQueryParams());
         let uri = new Soup.URI(BASE_URL + '/' + API_VERSION + '/trip?' +
                                query.toString());
         let request = new Soup.Message({ method: 'GET', uri: uri });
@@ -292,7 +292,7 @@ var Resrobot = class Resrobot {
         walkingLeg.agencyTimezoneOffset = tzOffset;
 
         let walkingItinerary =
-            new TransitPlan.Itinerary({ legs: [walkingLeg]} );
+            new Itinerary({ legs: [walkingLeg]} );
 
         walkingItinerary.adjustTimings();
 
@@ -318,7 +318,7 @@ var Resrobot = class Resrobot {
 
     _createItinerary(trip) {
         let legs = this._createLegs(trip.LegList.Leg);
-        let itinerary = new TransitPlan.Itinerary({ legs: legs });
+        let itinerary = new Itinerary({ legs: legs });
 
         itinerary.adjustTimings();
 
@@ -438,24 +438,24 @@ var Resrobot = class Resrobot {
         let polyline = this._createPolylineForLeg(leg);
         let duration = leg.duration ? this._parseDuration(leg.duration) : null;
 
-        let result = new TransitPlan.Leg({ departure:            departure,
-                                           arrival:              arrival,
-                                           from:                 from,
-                                           to:                   to,
-                                           headsign:             leg.direction,
-                                           fromCoordinate:       [origin.lat,
-                                                                  origin.lon],
-                                           toCoordinate:         [destination.lat,
-                                                                  destination.lon],
-                                           route:                route,
-                                           routeType:            routeType,
-                                           polyline:             polyline,
-                                           isTransit:            isTransit,
-                                           distance:             leg.dist,
-                                           duration:             duration,
-                                           agencyName:           agencyName,
-                                           agencyTimezoneOffset: tzOffset,
-                                           tripShortName:        route });
+        let result = new Leg({ departure:            departure,
+                               arrival:              arrival,
+                               from:                 from,
+                               to:                   to,
+                               headsign:             leg.direction,
+                               fromCoordinate:       [origin.lat,
+                                                      origin.lon],
+                               toCoordinate:         [destination.lat,
+                                                      destination.lon],
+                               route:                route,
+                               routeType:            routeType,
+                               polyline:             polyline,
+                               isTransit:            isTransit,
+                               distance:             leg.dist,
+                               duration:             duration,
+                               agencyName:           agencyName,
+                               agencyTimezoneOffset: tzOffset,
+                               tripShortName:        route });
 
         if (isTransit)
             result.intermediateStops = this._createIntermediateStops(leg);
@@ -512,11 +512,11 @@ var Resrobot = class Resrobot {
         if (!departure)
             departure = arrival;
 
-        return new TransitPlan.Stop({ name:                 stop.name,
-                                      arrival:              arrival,
-                                      departure:            departure,
-                                      agencyTimezoneOffset: departureTzOffset || arrivalTzOffset,
-                                      coordinate: [stop.lat, stop.lon] });
+        return new Stop({ name:                 stop.name,
+                          arrival:              arrival,
+                          departure:            departure,
+                          agencyTimezoneOffset: departureTzOffset || arrivalTzOffset,
+                          coordinate: [stop.lat, stop.lon] });
     }
 
     _getHVTCodeFromCatCode(code) {
@@ -603,15 +603,15 @@ var Resrobot = class Resrobot {
 
     _productCodeForTransitType(type) {
         switch (type) {
-            case TransitPlan.RouteType.BUS:
+            case RouteType.BUS:
                 return Products.BUS + Products.EXPRESS_BUS + Products.TAXI;
-            case TransitPlan.RouteType.TRAM:
+            case RouteType.TRAM:
                 return Products.TRAM;
-            case TransitPlan.RouteType.TRAIN:
+            case RouteType.TRAIN:
                 return Products.EXPRESS_TRAIN + Products.LOCAL_TRAIN;
-            case TransitPlan.RouteType.SUBWAY:
+            case RouteType.SUBWAY:
                 return Products.SUBWAY;
-            case TransitPlan.RouteType.FERRY:
+            case RouteType.FERRY:
                 return Products.FERRY;
             default:
                 return 0;
diff --git a/src/translations.js b/src/translations.js
index 417811e4..6106c33d 100644
--- a/src/translations.js
+++ b/src/translations.js
@@ -19,13 +19,15 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
-const C_ = imports.gettext.dgettext;
+import gettext from 'gettext';
 
-const GLib = imports.gi.GLib;
+const _ = gettext.gettext;
+const C_ = gettext.dgettext;
 
-const Time = imports.time;
-const Utils = imports.utils;
+import GLib from 'gi://GLib';
+
+import * as Time from './time.js';
+import * as Utils from './utils.js';
 
 /* Translate an opening time specification tag value.
  * from OSM into a "two-dimensional" (array-of-arrays) grid of human-readable
@@ -47,7 +49,7 @@ const Utils = imports.utils;
  * The definition for the opening_hours tag can be found at:
  * http://wiki.openstreetmap.org/wiki/Key:opening_hours
  */
-function translateOpeningHours(string) {
+export function translateOpeningHours(string) {
     if (string === '24/7' || string === 'Mo-Su 00:00-24:00' ||
         string === '00:00-24:00')
         return [[_("Around the clock")]];
@@ -71,7 +73,7 @@ function translateOpeningHours(string) {
  * Mo-We,Fr 10:00-12:00,13:00-17:00
  * Mo-We,Fr 10:00-12:00, 13:00-17:00
  */
-function _translateOpeningHoursPart(string) {
+export function _translateOpeningHoursPart(string) {
     let splitString = string.split(/\s+/);
     let len = splitString.length;
 
@@ -99,7 +101,7 @@ function _translateOpeningHoursPart(string) {
  * Mo-Fr
  * Mo,We,Th-Fr
  */
-function _translateOpeningHoursDayIntervalList(string) {
+export function _translateOpeningHoursDayIntervalList(string) {
     let splitParts = string.split(',');
     let interval1, interval2, interval3;
 
@@ -146,7 +148,7 @@ function _translateOpeningHoursDayIntervalList(string) {
  * Mo-Fr
  * Tu
  */
-function _translateOpeningHoursDayInterval(string) {
+export function _translateOpeningHoursDayInterval(string) {
     let splitString = string.split('-');
 
     // special case: Mo-Su treated as "every day"
@@ -279,7 +281,7 @@ function _translateOpeningHoursTime(string) {
     }
 }
 
-function translateReligion(string) {
+export function translateReligion(string) {
     switch(string) {
     case 'animist': return _("Animism");
     case 'bahai': return_("Bahá'í");
diff --git a/src/turnPointMarker.js b/src/turnPointMarker.js
index c5e872ee..7548f6cf 100644
--- a/src/turnPointMarker.js
+++ b/src/turnPointMarker.js
@@ -19,57 +19,59 @@
  * Author: Dario Di Nucci <linkin88mail gmail com>
  */
 
-const Clutter = imports.gi.Clutter;
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
+import Clutter from 'gi://Clutter';
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const Color = imports.color;
-const Location = imports.location;
-const MapMarker = imports.mapMarker;
-const Place = imports.place;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import * as Color from './color.js';
+import {Location} from './location.js';
+import {MapMarker} from './mapMarker.js';
+import {Place} from './place.js';
+import * as Utils from './utils.js';
 
-var TurnPointMarker = GObject.registerClass(
-class TurnPointMarker extends MapMarker.MapMarker {
+export class TurnPointMarker extends MapMarker {
 
-    _init(params) {
-        this._queryPoint = params.queryPoint;
+    constructor(params) {
+        let queryPoint = params.queryPoint;
         delete params.queryPoint;
 
-        this._turnPoint = params.turnPoint;
+        let turnPoint = params.turnPoint;
         delete params.turnPoint;
 
-        this._transitStop = params.transitStop;
+        let transitStop = params.transitStop;
         delete params.transitStop;
 
-        this._transitLeg = params.transitLeg;
+        let transitLeg = params.transitLeg;
         delete params.transitLeg;
 
         let latitude;
         let longitude;
 
-        if (this._turnPoint) {
-            latitude = this._turnPoint.coordinate.get_latitude();
-            longitude = this._turnPoint.coordinate.get_longitude();
+        if (turnPoint) {
+            latitude = turnPoint.coordinate.get_latitude();
+            longitude = turnPoint.coordinate.get_longitude();
         } else {
-            latitude = this._transitStop.coordinate[0];
-            longitude = this._transitStop.coordinate[1];
+            latitude = transitStop.coordinate[0];
+            longitude = transitStop.coordinate[1];
         }
 
-        params.place = new Place.Place({
-            location: new Location.Location({ latitude: latitude,
-                                              longitude: longitude }) });
-        super._init(params);
+        params.place =
+            new Place({ location: new Location({ latitude: latitude,
+                                                 longitude: longitude }) });
+
+        super(params);
+
+        this._queryPoint = queryPoint;
 
         let actor;
         if (this._queryPoint) {
             this.draggable = true;
             this.connect('drag-finish', () => this._onMarkerDrag());
-            actor = this._actorFromIconName(this._turnPoint.iconName, 0);
+            actor = this._actorFromIconName(turnPoint.iconName, 0);
         } else {
-            let color = this._getColor();
+            let color = this._getColor(transitLeg);
             actor = this._actorFromIconName('maps-point-end-symbolic',
                                             0,
                                             color);
@@ -77,12 +79,12 @@ class TurnPointMarker extends MapMarker.MapMarker {
         this.add_actor(actor);
     }
 
-    _getColor() {
+    _getColor(transitLeg) {
         /* Use the route color from the transit leg when representing part of
          * a transit trip, otherwise let the fallback functionality of the
          * utility function use a GNOMEish blue color for turn-by-turn routing.
          */
-        let color = this._transitLeg ? this._transitLeg.color : null;
+        let color = transitLeg?.color;
 
         return new Gdk.RGBA({ red: Color.parseColor(color, 0, 33 / 255),
                               green: Color.parseColor(color, 1, 93 / 255),
@@ -114,10 +116,12 @@ class TurnPointMarker extends MapMarker.MapMarker {
 
     _onMarkerDrag() {
         let query = Application.routeQuery;
-        let place = new Place.Place({
-            location: new Location.Location({ latitude: this.latitude.toFixed(5),
-                                              longitude: this.longitude.toFixed(5) }) });
+        let place =
+            new Place({ location: new Location({ latitude: this.latitude.toFixed(5),
+                                                 longitude: this.longitude.toFixed(5) }) });
 
         this._queryPoint.place = place;
     }
-});
+}
+
+GObject.registerClass(TurnPointMarker);
diff --git a/src/uris.js b/src/uris.js
index 6575b222..5e69af05 100644
--- a/src/uris.js
+++ b/src/uris.js
@@ -19,12 +19,14 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+import gettext from 'gettext';
 
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
-const Utils = imports.utils;
+import * as Utils from './utils.js';
+
+const _ = gettext.gettext;
 
 // Matches URLs for OpenStreetMap (for addressing objects or coordinates)
 const OSM_URL_REGEX = new RegExp(/https?:\/\/(www\.)?openstreetmap\.org./);
@@ -34,7 +36,7 @@ const OSM_URL_REGEX = new RegExp(/https?:\/\/(www\.)?openstreetmap\.org./);
  * e.g. an openstreetmap.org URL with lat and lon query parameters,
  * returns [lat, lon, optional zoom], otherwise [].
  */
-function parseAsCoordinateURL(url) {
+export function parseAsCoordinateURL(url) {
     if (url.match(OSM_URL_REGEX)) {
         /* it seems #map= is not handle well by parse_params(), so just remove
          * the # as a work-around
@@ -89,7 +91,7 @@ function parseAsCoordinateURL(url) {
  * For URLs addressing a specific OSM object (node, way, or relation),
  * returns [type,id], otherwise [].
  */
-function parseAsObjectURL(url) {
+export function parseAsObjectURL(url) {
     if (url.match(OSM_URL_REGEX)) {
         let uri = GLib.Uri.parse(url, GLib.UriFlags.NONE);
         let path = uri.get_path();
@@ -113,7 +115,7 @@ function parseAsObjectURL(url) {
  * For maps: URIs, return the search query string if a valid URI
  * otherwise null.
  */
-function parseMapsURI(uri) {
+export function parseMapsURI(uri) {
     let path = uri.substring('maps:'.length);
     let [param, value] = Utils.splitAtFirst(path, '=');
 
diff --git a/src/userLocationMarker.js b/src/userLocationMarker.js
index 6181d238..55d9d85f 100644
--- a/src/userLocationMarker.js
+++ b/src/userLocationMarker.js
@@ -19,40 +19,41 @@
  * Author: Damián Nohales <damiannohales gmail com>
  */
 
-const Champlain = imports.gi.Champlain;
-const Clutter = imports.gi.Clutter;
-const GObject = imports.gi.GObject;
+import Champlain from 'gi://Champlain';
+import Clutter from 'gi://Clutter';
+import GObject from 'gi://GObject';
 
-const MapMarker = imports.mapMarker;
+import {MapMarker} from './mapMarker.js';
 
-var AccuracyCircleMarker = GObject.registerClass(
-class AccuracyCirleMarker extends Champlain.Point {
+export class AccuracyCircleMarker extends Champlain.Point {
 
-    _init(params) {
-        this.place = params.place;
+    constructor(params) {
+        let place = params.place;
         delete params.place;
 
         params.color = new Clutter.Color({ red: 0,
                                            blue: 255,
                                            green: 0,
                                            alpha: 25 });
-        params.latitude = this.place.location.latitude;
-        params.longitude = this.place.location.longitude;
+        params.latitude = place.location.latitude;
+        params.longitude = place.location.longitude;
         params.reactive = false;
 
-        super._init(params);
+        super(params);
+
+        this._place = place;
     }
 
     refreshGeometry(view) {
-        this.latitude = this.place.location.latitude;
-        this.longitude = this.place.location.longitude;
+        this.latitude = this._place.location.latitude;
+        this.longitude = this._place.location.longitude;
 
         let zoom = view.zoom_level;
         let source = view.map_source;
         let metersPerPixel = source.get_meters_per_pixel(zoom,
                                                          this.latitude,
                                                          this.longitude);
-        let size = this.place.location.accuracy * 2 / metersPerPixel;
+        let size = this._place.location.accuracy * 2 / metersPerPixel;
 
         if (size > view.width || size > view.height)
             this.hide();
@@ -61,13 +62,14 @@ class AccuracyCirleMarker extends Champlain.Point {
             this.show();
         }
     }
-});
+}
+
+GObject.registerClass(AccuracyCircleMarker);
 
-var UserLocationMarker = GObject.registerClass(
-class UserLocationMarker extends MapMarker.MapMarker {
+export class UserLocationMarker extends MapMarker {
 
-    _init(params) {
-        super._init(params);
+    constructor(params) {
+        super(params);
 
         this._accuracyMarker = new AccuracyCircleMarker({ place: this.place });
         this.connect('notify::view-zoom-level',
@@ -123,4 +125,6 @@ class UserLocationMarker extends MapMarker.MapMarker {
             this._accuracyMarker.visible = false;
         }
     }
-});
+}
+
+GObject.registerClass(UserLocationMarker);
diff --git a/src/utils.js b/src/utils.js
index 9c8ec3fd..91f88937 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -20,21 +20,24 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const _ = imports.gettext.gettext;
-const ngettext = imports.gettext.ngettext;
-
-const GLib = imports.gi.GLib;
-const Gdk = imports.gi.Gdk;
-const GdkPixbuf = imports.gi.GdkPixbuf;
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const Gtk = imports.gi.Gtk;
-const GWeather = imports.gi.GWeather;
-const Soup = imports.gi.Soup;
+import gettext from 'gettext';
+
+import GLib from 'gi://GLib';
+import Gdk from 'gi://Gdk';
+import GdkPixbuf from 'gi://GdkPixbuf';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import Gtk from 'gi://Gtk';
+import GWeather from 'gi://GWeather';
+import Soup from 'gi://Soup';
+
+const _ = gettext.gettext;
+const ngettext = gettext.ngettext;
+
 const ByteArray = imports.byteArray;
 
-var METRIC_SYSTEM = 1;
-var IMPERIAL_SYSTEM = 2;
+export const METRIC_SYSTEM = 1;
+export const IMPERIAL_SYSTEM = 2;
 
 //List of locales using imperial system according to glibc locale database
 const IMPERIAL_LOCALES = ['unm_US', 'es_US', 'es_PR', 'en_US', 'yi_US'];
@@ -53,9 +56,14 @@ const _integerTwoDigitFormat =
 let debugInit = false;
 let measurementSystem = null;
 
-var debugEnabled = false;
+// this should only be used by the unit test to hard-set the measurement system
+export function _setMeasurementSystem(m) {
+    measurementSystem = m;
+}
+
+export var debugEnabled = false;
 
-function debug(msg) {
+export function debug(msg) {
     if (!debugInit) {
         let env = GLib.getenv('MAPS_DEBUG');
         if (env)
@@ -72,14 +80,14 @@ function debug(msg) {
 }
 
 // Connect to a signal on an object and disconnect on its first emission.
-function once(obj, signal, callback) {
+export function once(obj, signal, callback) {
     let id = obj.connect(signal, function() {
         obj.disconnect(id);
         callback();
     });
 }
 
-function loadStyleSheet(file) {
+export function loadStyleSheet(file) {
     let provider = new Gtk.CssProvider();
     provider.load_from_file(file);
     Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
@@ -87,7 +95,7 @@ function loadStyleSheet(file) {
                                              Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
 }
 
-function addActions(actionMap, entries, settings = null) {
+export function addActions(actionMap, entries, settings = null) {
     for(let name in entries) {
         let entry = entries[name];
         let action = createAction(name, entry, settings);
@@ -99,7 +107,7 @@ function addActions(actionMap, entries, settings = null) {
     }
 }
 
-function setAccelsForActionMap(actionMap, actionName, accels) {
+export function setAccelsForActionMap(actionMap, actionName, accels) {
     let app;
     let prefix;
 
@@ -154,7 +162,7 @@ function _getPlatformData(appId, timestamp) {
     return { 'desktop-startup-id': id };
 }
 
-function activateAction(appId, action, parameter, timestamp) {
+export function activateAction(appId, action, parameter, timestamp) {
     let objectPath = '/' + appId.replace(/\./g, '/');
     let platformData = _getPlatformData(appId, timestamp);
     let wrappedParam = parameter ? [parameter] : [];
@@ -176,13 +184,13 @@ function activateAction(appId, action, parameter, timestamp) {
                           });
 }
 
-function dashedToCamelCase(name) {
+export function dashedToCamelCase(name) {
     return name.replace(/(-.)/g, function(x) {
         return x[1].toUpperCase();
     });
 }
 
-function getUIObject(res, ids) {
+export function getUIObject(res, ids) {
     let builder = new Gtk.Builder();
     builder.add_from_resource('/org/gnome/Maps/ui/' + res + '.ui');
     let ret = {};
@@ -192,7 +200,7 @@ function getUIObject(res, ids) {
     return ret;
 }
 
-function readFile(filename) {
+export function readFile(filename) {
     let status, buffer;
     let file = Gio.File.new_for_path(filename);
     try {
@@ -206,7 +214,7 @@ function readFile(filename) {
         return null;
 }
 
-function writeFile(filename, buffer) {
+export function writeFile(filename, buffer) {
     let file = Gio.File.new_for_path(filename);
     let status;
     try {
@@ -217,7 +225,7 @@ function writeFile(filename, buffer) {
     }
 }
 
-function getMeasurementSystem() {
+export function getMeasurementSystem() {
     if (measurementSystem)
         return measurementSystem;
 
@@ -238,15 +246,15 @@ function getMeasurementSystem() {
 /**
  * Get the highest priority bare lange currently in use.
  */
-function getLanguage() {
+export function getLanguage() {
     let locale = GLib.get_language_names()[0];
     // the last item returned is the "bare" language
     return GLib.get_locale_variants(locale).slice(-1)[0];
 }
 
-function getAccuracyDescription(accuracy) {
+export function getAccuracyDescription(accuracy) {
     switch(accuracy) {
-    case Geocode.LOCATION_ACCURACY_UNKNOWN:
+    case GeocodeGlib.LOCATION_ACCURACY_UNKNOWN:
         /* Translators: Accuracy of user location information */
         return _("Unknown");
     case 0:
@@ -257,7 +265,7 @@ function getAccuracyDescription(accuracy) {
     }
 }
 
-function loadAvatar(pixbuf, size) {
+export function loadAvatar(pixbuf, size) {
     let width = pixbuf.get_width();
     let height = pixbuf.get_height();
     let croppedThumbnail;
@@ -273,7 +281,7 @@ function loadAvatar(pixbuf, size) {
     return croppedThumbnail.scale_simple(size, size, GdkPixbuf.InterpType.BILINEAR);
 }
 
-function load_icon(icon, size, loadCompleteCallback) {
+export function load_icon(icon, size, loadCompleteCallback) {
     if (icon instanceof Gio.FileIcon || icon instanceof Gio.BytesIcon) {
         _load_icon(icon, loadCompleteCallback);
     } else if (icon instanceof Gio.ThemedIcon) {
@@ -307,11 +315,11 @@ function _load_themed_icon(icon, size, loadCompleteCallback) {
     }
 }
 
-function osmTypeToString(osmType) {
+export function osmTypeToString(osmType) {
     switch(osmType) {
-        case Geocode.PlaceOsmType.NODE: return 'node';
-        case Geocode.PlaceOsmType.RELATION: return 'relation';
-        case Geocode.PlaceOsmType.WAY: return 'way';
+        case GeocodeGlib.PlaceOsmType.NODE: return 'node';
+        case GeocodeGlib.PlaceOsmType.RELATION: return 'relation';
+        case GeocodeGlib.PlaceOsmType.WAY: return 'way';
         default: return 'node';
     }
 }
@@ -320,7 +328,7 @@ function osmTypeToString(osmType) {
  * Return a formatted integer number with no
  * fraction, using locale-specific numerals
  */
-function formatLocaleInteger(n) {
+export function formatLocaleInteger(n) {
     return _integerFormat.format(n);
 }
 
@@ -329,11 +337,11 @@ function formatLocaleInteger(n) {
  * fraction, using locale-specific numerals using at least two digits
  * with possible leading 0, suitable for time rendering.
  */
-function formatLocaleIntegerMinimumTwoDigits(n) {
+export function formatLocaleIntegerMinimumTwoDigits(n) {
     return _integerTwoDigitFormat.format(n);
 }
 
-function prettyTime(time) {
+export function prettyTime(time) {
     let seconds = Math.floor(time / 1000);
     let minutes = Math.floor(seconds / 60);
     seconds = seconds % 60;
@@ -371,7 +379,7 @@ function prettyTime(time) {
     }
 }
 
-function prettyDistance(distance, noRound) {
+export function prettyDistance(distance, noRound) {
     if (getMeasurementSystem() === METRIC_SYSTEM) {
         // round to whole meters
         distance = Math.round(distance);
@@ -402,14 +410,14 @@ function prettyDistance(distance, noRound) {
  * to handle estimated values without showing lots of zeros.
  * Other values are formatted in full.
  */
-function prettyPopulation(population) {
+export function prettyPopulation(population) {
     let notation = population >= 1000000 && population % 100000 === 0 ?
                    'compact' : 'standard';
 
     return population.toLocaleString(undefined, { notation: notation });
 }
 
-function uriSchemeSupported(scheme) {
+export function uriSchemeSupported(scheme) {
     let apps = Gio.AppInfo.get_all();
     let prefix = 'x-scheme-handler/';
 
@@ -426,25 +434,25 @@ function uriSchemeSupported(scheme) {
     return false;
 }
 
-function normalizeString(string) {
+export function normalizeString(string) {
     let normalized = GLib.utf8_normalize(string, -1, GLib.NormalizeMode.ALL);
     return normalized.replace(ACCENTS_REGEX, '');
 }
 
-function isUsingDarkThemeVariant() {
+export function isUsingDarkThemeVariant() {
     let gtkSettings = Gtk.Settings.get_default();
 
     return gtkSettings.gtk_application_prefer_dark_theme;
 }
 
-function isUsingHighContrastTheme() {
+export function isUsingHighContrastTheme() {
     let gtkSettings = Gtk.Settings.get_default();
     let themeName = gtkSettings.gtk_theme_name;
 
     return themeName === 'HighContrast' || themeName === 'HighContrastInverse';
 }
 
-function showDialog(msg, type, transientFor) {
+export function showDialog(msg, type, transientFor) {
     let messageDialog =
         new Gtk.MessageDialog({ transient_for: transientFor,
                                 destroy_with_parent: true,
@@ -460,7 +468,7 @@ function showDialog(msg, type, transientFor) {
 /* Gets a string from either a ByteArray or Uint8Array. This is for
 compatibility between two different Gjs versions, see discussion at
 https://gitlab.gnome.org/GNOME/gnome-maps/merge_requests/19 */
-function getBufferText(buffer) {
+export function getBufferText(buffer) {
     if (buffer instanceof Uint8Array) {
         return ByteArray.toString(buffer);
     } else {
@@ -468,14 +476,14 @@ function getBufferText(buffer) {
     }
 }
 
-function getCountryCodeForCoordinates(lat, lon) {
+export function getCountryCodeForCoordinates(lat, lon) {
     let location = GWeather.Location.new_detached('', null, lat, lon);
 
     return location.get_country();
 }
 
 /* Determines whether a URI is valid and its scheme is HTTP or HTTPS. */
-function isValidWebsite(website) {
+export function isValidWebsite(website) {
     try {
         GLib.Uri.is_valid(website, GLib.UriFlags.NONE);
     } catch(e) {
@@ -485,7 +493,7 @@ function isValidWebsite(website) {
 }
 
 /* Determine whether a string is a valid e-mail address. */
-function isValidEmail(email) {
+export function isValidEmail(email) {
     // if it starts with 'mailto:', it's probably a mistake copy-pasting a URI
     if (email.startsWith('mailto:'))
         return false;
@@ -496,14 +504,14 @@ function isValidEmail(email) {
 /* Return string with first character in upper case according the rules
  * determined by the current locale
  */
-function firstToLocaleUpperCase(str) {
+export function firstToLocaleUpperCase(str) {
     return str[0].toLocaleUpperCase() + str.substring(1);
 }
 
 /* Splits string at first occurance of a character, leaving remaining
  * occurances of the separator in the second part
  */
-function splitAtFirst(string, separator) {
+export function splitAtFirst(string, separator) {
     let [first, ...rest] = string.split(separator);
 
     if (rest.length > 0) {
diff --git a/src/wikipedia.js b/src/wikipedia.js
index daf3dc44..4629d06d 100644
--- a/src/wikipedia.js
+++ b/src/wikipedia.js
@@ -19,13 +19,13 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GdkPixbuf = imports.gi.GdkPixbuf;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import GdkPixbuf from 'gi://GdkPixbuf';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
 const Format = imports.format;
-const Utils = imports.utils;
+import * as Utils from './utils.js';
 
 /**
  * Regex matching editions of Wikipedia, e.g. "en", "arz", pt-BR", "simple".
@@ -45,16 +45,16 @@ function _getSoupSession() {
 let _thumbnailCache = {};
 let _metadataCache = {};
 
-function getLanguage(wiki) {
+export function getLanguage(wiki) {
     return wiki.split(':')[0];
 }
 
-function getArticle(wiki) {
+export function getArticle(wiki) {
     return Soup.uri_encode(wiki.replace(/ /g, '_').split(':').splice(1).join(':'),
                            '\'');
 }
 
-function getHtmlEntityEncodedArticle(wiki) {
+export function getHtmlEntityEncodedArticle(wiki) {
     return GLib.markup_escape_text(wiki.split(':').splice(1).join(':'), -1);
 }
 
@@ -62,7 +62,7 @@ function getHtmlEntityEncodedArticle(wiki) {
  * Determine if a Wikipedia reference tag is valid
  * (of the form "lang:Article title")
  */
-function isValidWikipedia(wiki) {
+export function isValidWikipedia(wiki) {
     let parts = wiki.split(':');
 
     if (parts.length < 2)
@@ -86,7 +86,7 @@ function isValidWikipedia(wiki) {
  * Calls @thumbnailCb with the Gdk.Pixbuf of the icon when successful, otherwise
  * null.
  */
-function fetchArticleInfo(wiki, size, metadataCb, thumbnailCb) {
+export function fetchArticleInfo(wiki, size, metadataCb, thumbnailCb) {
     let lang = getLanguage(wiki);
     let title = getHtmlEntityEncodedArticle(wiki);
     let uri = Format.vprintf('https://%s.wikipedia.org/w/api.php', [ lang ]);
diff --git a/src/xmldom/dom.js b/src/xmldom/dom.js
index 0ec86d14..8421e9c4 100644
--- a/src/xmldom/dom.js
+++ b/src/xmldom/dom.js
@@ -250,7 +250,7 @@ NamedNodeMap.prototype = {
 /**
  * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
  */
-function DOMImplementation(/* Object */ features) {
+export function DOMImplementation(/* Object */ features) {
        this._features = {};
        if (features) {
                for (var feature in features) {
@@ -907,7 +907,7 @@ function ProcessingInstruction() {
 }
 ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
 _extends(ProcessingInstruction,Node);
-function XMLSerializer(){}
+export function XMLSerializer(){}
 XMLSerializer.prototype.serializeToString = function(node,attributeSorter){
        return node.toString(attributeSorter);
 }
diff --git a/src/xmldom/domparser.js b/src/xmldom/domparser.js
index 10bc45bc..421af21d 100644
--- a/src/xmldom/domparser.js
+++ b/src/xmldom/domparser.js
@@ -1,7 +1,7 @@
-const XMLReader = imports.xmldom.sax.XMLReader;
-const DOMImplementation = imports.xmldom.dom.DOMImplementation;
+import {XMLReader} from './sax.js';
+import {DOMImplementation} from './dom.js';
 
-function DOMParser(options){
+export function DOMParser(options){
        this.options = options ||{locator:{}};
 }
 DOMParser.prototype.parseFromString = function(source,mimeType){       
@@ -243,4 +243,4 @@ function appendElement (hander,node) {
     } else {
         hander.currentElement.appendChild(node);
     }
-}//appendChild and setAttributeNS are preformance key
+}//appendChild and setAttributeNS are preformance key
diff --git a/src/xmldom/sax.js b/src/xmldom/sax.js
index 9be75bfa..63f9ab05 100644
--- a/src/xmldom/sax.js
+++ b/src/xmldom/sax.js
@@ -18,7 +18,7 @@ var S_E = 5;//attr value end and no space(quot end)
 var S_S = 6;//(attr value end || tag end ) && (space offer)
 var S_C = 7;//closed el<el />
 
-function XMLReader(){
+export function XMLReader(){
        
 }
 
@@ -579,4 +579,4 @@ function split(source,start){
                if(match[1])return buf;
        }
        return null;
-}
+}
diff --git a/src/zoomInDialog.js b/src/zoomInDialog.js
index 16bb9c99..c7fd7b6b 100644
--- a/src/zoomInDialog.js
+++ b/src/zoomInDialog.js
@@ -20,30 +20,29 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const OSMEdit = imports.osmEdit;
+import {OSMEdit} from './osmEdit.js';
 
-var ZoomInDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/zoom-in-dialog.ui',
-    InternalChildren: [ 'cancelButton',
-                        'zoomInButton'],
-}, class ZoomInDialog extends Gtk.Dialog {
+export class ZoomInDialog extends Gtk.Dialog {
 
-    _init(params) {
-        this._latitude = params.latitude;
+    constructor(params) {
+        let latitude = params.latitude;
         delete params.latitude;
-        this._longitude = params.longitude;
+        let longitude = params.longitude;
         delete params.longitude;
-        this._view = params.view;
+        let view = params.view;
         delete params.view;
 
         /* This is a construct-only property and cannot be set by GtkBuilder */
         params.use_header_bar = true;
 
-        super._init(params);
+        super(params);
 
+        this._latitude = latitude;
+        this._longitude = longitude;
+        this._view = view;
         this._zoomInButton.connect('clicked', () => this._onZoomIn());
         this._cancelButton.connect('clicked', () => this._onCancel());
     }
@@ -59,4 +58,10 @@ var ZoomInDialog = GObject.registerClass({
     _onCancel() {
         this.response(Gtk.ResponseType.CANCEL);
     }
-});
\ No newline at end of file
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/zoom-in-dialog.ui',
+    InternalChildren: [ 'cancelButton',
+                        'zoomInButton'],
+}, ZoomInDialog);
diff --git a/tests/addressTest.js b/tests/addressTest.js
index 811a2cee..32962da2 100644
--- a/tests/addressTest.js
+++ b/tests/addressTest.js
@@ -21,11 +21,7 @@
 
 const JsUnit = imports.jsUnit;
 
-const Address = imports.address;
-
-function main() {
-    streetAddressForCountryCodeTest();
-}
+import * as Address from './address.js';
 
 function streetAddressForCountryCodeTest() {
     // Test known expected address formats for some countries
@@ -57,3 +53,5 @@ function streetAddressForCountryCodeTest() {
                         Address.streetAddressForCountryCode('Some Street',
                                                             '42', 'UT'));
 }
+
+streetAddressForCountryCodeTest();
diff --git a/tests/boundingBoxTest.js b/tests/boundingBoxTest.js
index d8a605e1..707059be 100644
--- a/tests/boundingBoxTest.js
+++ b/tests/boundingBoxTest.js
@@ -21,8 +21,8 @@
 
 const JsUnit = imports.jsUnit;
 
-const BoundingBox = imports.boundingBox;
-const Constants = imports.constants;
+import {BoundingBox} from './boundingBox.js';
+import * as Constants from './constants.js';
 
 function main() {
     constructTest();
@@ -36,8 +36,8 @@ function main() {
 }
 
 function constructTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
 
     JsUnit.assertEquals(60.0, bbox.top);
     JsUnit.assertEquals(15.0, bbox.left);
@@ -45,7 +45,7 @@ function constructTest() {
     JsUnit.assertEquals(16.0, bbox.right);
 
     // test default values
-    bbox = new BoundingBox.BoundingBox();
+    bbox = new BoundingBox();
 
     JsUnit.assertEquals(Constants.MIN_LATITUDE, bbox.top);
     JsUnit.assertEquals(Constants.MAX_LONGITUDE, bbox.left);
@@ -54,8 +54,8 @@ function constructTest() {
 }
 
 function copyTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
     let copy = bbox.copy();
 
     // update original box
@@ -72,7 +72,7 @@ function copyTest() {
 }
 
 function setTest() {
-    let bbox = new BoundingBox.BoundingBox();
+    let bbox = new BoundingBox();
 
     bbox.top = 0;
     bbox.left = 0;
@@ -86,8 +86,8 @@ function setTest() {
 }
 
 function getCenterTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
     let center = bbox.getCenter();
 
     JsUnit.assertTrue(center instanceof Array);
@@ -97,10 +97,10 @@ function getCenterTest() {
 }
 
 function composeTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
-    let other = new BoundingBox.BoundingBox({ top: 60.0, left: 14.0,
-                                              bottom: 59.0, right: 15.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
+    let other = new BoundingBox({ top: 60.0, left: 14.0,
+                                  bottom: 59.0, right: 15.0 });
 
     bbox.compose(other);
 
@@ -111,8 +111,8 @@ function composeTest() {
 }
 
 function extendTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
 
     bbox.extend(58.0, 14.0);
 
@@ -123,31 +123,33 @@ function extendTest() {
 }
 
 function isValidTest() {
-    let valid = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                              bottom: 59.0, right: 16.0 });
+    let valid = new BoundingBox({ top: 60.0, left: 15.0,
+                                  bottom: 59.0, right: 16.0 });
 
     JsUnit.assertTrue(valid.isValid());
 
-    let unset = new BoundingBox.BoundingBox();
+    let unset = new BoundingBox();
 
     JsUnit.assertFalse(unset.isValid());
 
-    let overflowNorth = new BoundingBox.BoundingBox({ top: 100.0, left: 15.0,
-                                                      bottom: 0.0, right: 16.0 });
+    let overflowNorth = new BoundingBox({ top: 100.0, left: 15.0,
+                                          bottom: 0.0, right: 16.0 });
 
     JsUnit.assertFalse(overflowNorth.isValid());
 
-    let flipped = new BoundingBox.BoundingBox({ top: 59.0, left: 16.0,
-                                                bottom: 60.0, right: 15.0 });
+    let flipped = new BoundingBox({ top: 59.0, left: 16.0,
+                                    bottom: 60.0, right: 15.0 });
 
     JsUnit.assertFalse(flipped.isValid());
 }
 
 function coversTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
 
     JsUnit.assertTrue(bbox.covers(59.5, 15.5));
     JsUnit.assertFalse(bbox.covers(0.0, 0.0));
     JsUnit.assertFalse(bbox.covers(59.0, -180.0));
 }
+
+main();
diff --git a/tests/colorTest.js b/tests/colorTest.js
index 0c231cf1..cc37d1b5 100644
--- a/tests/colorTest.js
+++ b/tests/colorTest.js
@@ -21,14 +21,7 @@
 
 const JsUnit = imports.jsUnit;
 
-const Color = imports.color;
-
-function main() {
-    parseColorTest();
-    relativeLuminanceTest();
-    contrastRatioTest();
-    getContrastingForegroundColorTest();
-}
+import * as Color from './color.js';
 
 function parseColorTest() {
     JsUnit.assertEquals(1.0, Color.parseColor('ff0000', 0));
@@ -69,3 +62,8 @@ function getContrastingForegroundColorTest() {
     JsUnit.assertEquals('dddddd',
                         Color.getContrastingForegroundColor('000088', 'dddddd'));
 }
+
+parseColorTest();
+relativeLuminanceTest();
+contrastRatioTest();
+getContrastingForegroundColorTest();
diff --git a/tests/meson.build b/tests/meson.build
index 51a600f0..32ccc8ae 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -2,6 +2,14 @@ tests = ['addressTest', 'boundingBoxTest', 'colorTest', 'osmNamesTest',
          'placeIconsTest', 'placeZoomTest', 'timeTest', 'translationsTest',
          'utilsTest', 'urisTest', 'wikipediaTest']
 
+# suffix for source resources (so we get /org/gnome/Maps or
+# /org/gnome/Maps/Devel, depending on the profile)
+if (get_option('profile') == 'development')
+       suffix = '/Devel'
+else
+       suffix = ''
+endif
+
 foreach test : tests
   script_conf = configuration_data()
   script_conf.set('GJS', gjs.path())
@@ -9,6 +17,7 @@ foreach test : tests
   script_conf.set('libdir', libdir)
   script_conf.set('prefix', prefix)
   script_conf.set('name', test)
+  script_conf.set('suffix', suffix)
   configure_file(
     input: 'test.in',
     output: test,
@@ -18,11 +27,30 @@ foreach test : tests
   )
 endforeach
 
+sources_conf = configuration_data()
+sources_conf.set('suffix', suffix)
+# include test sources
+sources_conf.set('testopencomment', '')
+sources_conf.set('testclosecomment', '')
+
+# generate combined GResource with source files and tests to use ES modules
+gnome.compile_resources(
+  'test.src',
+  configure_file(
+       input: '../src/org.gnome.Maps.src.gresource.xml.in',
+       output: 'test.src.gresource.xml',
+       configuration: sources_conf
+  ),
+  gresource_bundle: true,
+  install: true,
+  install_dir: meson.build_root(),
+  source_dir: ['../src', '../src/geojson-vt']
+)
+
 foreach test : tests
   test(test, gjs,
-       args: ['-I', meson.source_root() + '/src/', '-I',
-              meson.source_root() + '/tests/',
-              'tests/@0@'.format(test)],
+       args: ['tests/@0@'.format(test),
+              join_paths(meson.build_root(), 'tests', 'test.src.gresource')],
        env:  ['LANG=en_US.utf8', 'LC_ALL=en_US.utf8']
   )
 endforeach
diff --git a/tests/osmNamesTest.js b/tests/osmNamesTest.js
index 172688e8..5a5044b2 100644
--- a/tests/osmNamesTest.js
+++ b/tests/osmNamesTest.js
@@ -19,10 +19,10 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-pkg.require({ 'Gdk': '3.0',
-              'Gtk': '3.0' });
+import 'gi://Gdk?version=3.0';
+import 'gi://Gtk?version=3.0';
 
-const OSMNames = imports.osmNames;
+import * as OSMNames from './osmNames.js';
 
 const JsUnit = imports.jsUnit;
 
@@ -59,18 +59,18 @@ const TAGS4 = { 'name': 'Uppsala',
                 'name:sv': 'Uppsala',
                 'name:yi': 'אופסאלא'};
 
-function main() {
-    JsUnit.assertEquals('Name in language', 'Namn',
-                        OSMNames.getNameForLanguageAndCountry(TAGS1, 'sv', 'GB'));
-    JsUnit.assertEquals('Fallback when language not localized', 'Name',
-                        OSMNames.getNameForLanguageAndCountry(TAGS1, 'fi', 'GB'));
-    JsUnit.assertEquals('Legacy Japanese romanization tag', 'Shin Ōsaka',
-                        OSMNames.getNameForLanguageAndCountry(TAGS2, 'sv', 'JP'));
-    JsUnit.assertEquals('Japanese romanization tag', 'Shin Ōsaka',
-                        OSMNames.getNameForLanguageAndCountry(TAGS3, 'sv', 'JP'));
-    JsUnit.assertEquals('Explicit English', 'Shin-Osaka',
-                        OSMNames.getNameForLanguageAndCountry(TAGS3, 'en', 'JP'));
-    JsUnit.assertEquals('Available tag in similar alphabeth', 'Уппсала',
-                        OSMNames.getNameForLanguageAndCountry(TAGS4, 'uk', 'SE'));
-}
+JsUnit.assertEquals('Name in language', 'Namn',
+                    OSMNames.getNameForLanguageAndCountry(TAGS1, 'sv', 'GB'));
+JsUnit.assertEquals('Fallback when language not localized', 'Name',
+                    OSMNames.getNameForLanguageAndCountry(TAGS1, 'fi', 'GB'));
+JsUnit.assertEquals('Legacy Japanese romanization tag', 'Shin Ōsaka',
+                    OSMNames.getNameForLanguageAndCountry(TAGS2, 'sv', 'JP'));
+JsUnit.assertEquals('Japanese romanization tag', 'Shin Ōsaka',
+                    OSMNames.getNameForLanguageAndCountry(TAGS3, 'sv', 'JP'));
+JsUnit.assertEquals('Explicit English', 'Shin-Osaka',
+                    OSMNames.getNameForLanguageAndCountry(TAGS3, 'en', 'JP'));
+JsUnit.assertEquals('Available tag in similar alphabeth', 'Уппсала',
+                    OSMNames.getNameForLanguageAndCountry(TAGS4, 'uk', 'SE'));
+
+
 
diff --git a/tests/placeIconsTest.js b/tests/placeIconsTest.js
index 076f1a94..6394149d 100644
--- a/tests/placeIconsTest.js
+++ b/tests/placeIconsTest.js
@@ -20,7 +20,7 @@
  */
 const JsUnit = imports.jsUnit;
 
-const PlaceIcons = imports.placeIcons;
+import * as PlaceIcons from './placeIcons.js';
 
 /* use a minimal mock of Place, since Place throught dependencies requires
  * the GResources to be setup, so it can't easily be used from tests
@@ -40,11 +40,6 @@ class MockedPlace {
     }
 }
 
-function main() {
-    testKnownTypes();
-    testDefaultIcon();
-}
-
 // test some known place type → icon mappings
 function testKnownTypes() {
     let p1 = new MockedPlace({ osmKey: 'amenity', osmValue: 'restaurant' });
@@ -71,3 +66,6 @@ function testDefaultIcon() {
     JsUnit.assertEquals('map-marker-symbolic', PlaceIcons.getIconForPlace(p2));
     JsUnit.assertEquals('map-marker-symbolic', PlaceIcons.getIconForPlace(p3));
 }
+
+testKnownTypes();
+testDefaultIcon();
diff --git a/tests/placeZoomTest.js b/tests/placeZoomTest.js
index b99a16e8..27b147cd 100644
--- a/tests/placeZoomTest.js
+++ b/tests/placeZoomTest.js
@@ -20,27 +20,22 @@
  */
 const JsUnit = imports.jsUnit;
 
-const PlaceZoom = imports.placeZoom;
+import * as PlaceZoom from './placeZoom.js';
 
-function main() {
-    placeZoomTest();
-}
+// specific place types
+JsUnit.assertEquals(17,
+                    PlaceZoom.getZoomLevelForPlace({ osmKey:   'shop',
+                                                     osmValue: 'supermarket' }));
+JsUnit.assertEquals(4,
+                    PlaceZoom.getZoomLevelForPlace({ osmKey:   'place',
+                                                     osmValue: 'continent' }));
 
-function placeZoomTest() {
-    // specific place types
-    JsUnit.assertEquals(17,
-                        PlaceZoom.getZoomLevelForPlace({ osmKey:   'shop',
-                                                         osmValue: 'supermarket' }));
-    JsUnit.assertEquals(4,
-                        PlaceZoom.getZoomLevelForPlace({ osmKey:   'place',
-                                                         osmValue: 'continent' }));
+// fallback for for OSM key
+JsUnit.assertEquals(17,
+                    PlaceZoom.getZoomLevelForPlace({ osmKey:   'place',
+                                                     osmValue: 'other' }));
 
-    // fallback for for OSM key
-    JsUnit.assertEquals(17,
-                        PlaceZoom.getZoomLevelForPlace({ osmKey:   'place',
-                                                         osmValue: 'other' }));
+// undefined for not defined type
+JsUnit.assertUndefined(PlaceZoom.getZoomLevelForPlace({ osmKey:   'type',
+                                                        osmValue: 'other' }));
 
-    // undefined for not defined type
-    JsUnit.assertUndefined(PlaceZoom.getZoomLevelForPlace({ osmKey:   'type',
-                                                            osmValue: 'other' }));
-}
diff --git a/tests/test.in b/tests/test.in
index 1f3aeabe..a2ef7bc0 100644
--- a/tests/test.in
+++ b/tests/test.in
@@ -1,6 +1,20 @@
 #!@GJS@
+const Gio = imports.gi.Gio;
+
 imports.package.init({ name: "@name@",
                        version: "@PACKAGE_VERSION@",
                        prefix: "@prefix@",
                        libdir: "@libdir@" });
-imports.package.run(imports.@name@);
+
+log('program name: ' + imports.system.programInvocationName);
+log('ARG: ' + imports.system.programArgs);
+
+// manually load GResource from build tree for the generated test scripts
+let resource = Gio.Resource.load(imports.system.programArgs[0]);
+
+resource._register();
+
+import(`resource:///org/gnome/Maps@suffix@/js/@name@.js`).catch(error => {
+    console.error(error);
+    imports.system.exit(1);
+});
diff --git a/tests/timeTest.js b/tests/timeTest.js
index a2ea6c18..96803f2f 100644
--- a/tests/timeTest.js
+++ b/tests/timeTest.js
@@ -21,16 +21,11 @@
 
 const JsUnit = imports.jsUnit;
 
-const Time = imports.time;
-
-function main() {
-  formatTimeWithTZOffsetTest();
-  formatTimeFromHoursAndMinsTest();
-}
+import * as Time from './time.js';
 
 function formatTimeWithTZOffsetTest() {
     // mock to always use 24 hour format
-    Time._is12Hour = function () { return false; };
+    Time._setIs12HourFunction(() => { return false; });
 
     JsUnit.assertEquals('22:54',
                         Time.formatTimeWithTZOffset(1607982864000, 3600000));
@@ -38,7 +33,7 @@ function formatTimeWithTZOffsetTest() {
                         Time.formatTimeWithTZOffset(1607982864000, 0));
 
     // mock to always use 12 hour format
-    Time._is12Hour = function () { return true; };
+    Time._setIs12HourFunction(() => { return true; });
 
     JsUnit.assertEquals('10:54 PM',
                         Time.formatTimeWithTZOffset(1607982864000, 3600000));
@@ -46,16 +41,19 @@ function formatTimeWithTZOffsetTest() {
 
 function formatTimeFromHoursAndMinsTest() {
     // mock to always use 24 hour format
-    Time._is12Hour = function () { return false; };
+    Time._setIs12HourFunction(() => { return false; });
 
     JsUnit.assertEquals('12:34', Time.formatTimeFromHoursAndMins(12, 34));
     JsUnit.assertEquals('00:00', Time.formatTimeFromHoursAndMins(24, 0));
     JsUnit.assertEquals('12:01', Time.formatTimeFromHoursAndMins(12, 1));
 
     // mock to always use 12 hour format
-    Time._is12Hour = function () { return true; };
+    Time._setIs12HourFunction(() => { return true; });
 
     JsUnit.assertEquals('12:34 PM', Time.formatTimeFromHoursAndMins(12, 34));
     JsUnit.assertEquals('12:00 AM', Time.formatTimeFromHoursAndMins(24, 0));
     JsUnit.assertEquals('12:01 PM', Time.formatTimeFromHoursAndMins(12, 1));
 }
+
+formatTimeWithTZOffsetTest();
+formatTimeFromHoursAndMinsTest();
diff --git a/tests/translationsTest.js b/tests/translationsTest.js
index bd99a6b4..422c1b5e 100644
--- a/tests/translationsTest.js
+++ b/tests/translationsTest.js
@@ -19,13 +19,13 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-pkg.require({ 'Gdk': '3.0',
-              'Gtk': '3.0' });
+import 'gi://Gdk?version=3.0';
+import 'gi://Gtk?version=3.0';
 
 const JsUnit = imports.jsUnit;
 
-const Time = imports.time;
-const Translations = imports.translations;
+import * as Time from './time.js';
+import * as Translations from './translations.js';
 
 // sample with 3 components, one day-range, two single days, single time ranges
 const SAMPLE1 = 'Mo-Fr 09:00-18:00; Sa 10:00-15:00; Su 12:00-15:00';
@@ -56,179 +56,174 @@ const SAMPLE10 = 'Mo-Fr 09:00-12:00, 13:00-18:00; Sa,Su 10:00-14:00';
 pkg.initGettext();
 pkg.initFormat();
 
-function main() {
-  translateOpeningHoursTest();
-}
-
-function translateOpeningHoursTest() {
-    // mock to use 24-hour clock format
-    Time._is12Hour = function () { return false; };
-
-    let translated = Translations.translateOpeningHours(SAMPLE1);
-    JsUnit.assertEquals(3, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals('09:00-18:00', translated[0][1]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat', translated[1][0]);
-    JsUnit.assertEquals('10:00-15:00', translated[1][1]);
-    JsUnit.assertEquals(2, translated[2].length);
-    JsUnit.assertEquals('Sun', translated[2][0]);
-    JsUnit.assertEquals('12:00-15:00', translated[2][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE2);
-    JsUnit.assertEquals(2, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-    JsUnit.assertEquals('10:00-14:00', translated[1][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE3);
-    JsUnit.assertEquals(1, translated.length);
-    JsUnit.assertEquals(1, translated[0].length);
-    JsUnit.assertEquals('From sunrise to sunset', translated[0][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE4);
-    JsUnit.assertEquals(1, translated.length);
-    JsUnit.assertEquals(1, translated[0].length);
-    JsUnit.assertEquals('Around the clock', translated[0][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE5);
-    JsUnit.assertEquals(1, translated.length);
-    JsUnit.assertEquals(1, translated[0].length);
-    JsUnit.assertEquals('Around the clock', translated[0][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE6);
-    JsUnit.assertEquals(3, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals('09:00-18:00', translated[0][1]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat', translated[1][0]);
-    JsUnit.assertEquals('10:00-15:00', translated[1][1]);
-    JsUnit.assertEquals(2, translated[2].length);
-    JsUnit.assertEquals('Sun', translated[2][0]);
-    JsUnit.assertEquals('not open', translated[2][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE7);
-    JsUnit.assertEquals(2, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-    JsUnit.assertEquals('10:00-14:00', translated[1][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE8);
-    JsUnit.assertEquals(3, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-    JsUnit.assertEquals('10:00-14:00', translated[1][1]);
-    JsUnit.assertEquals(2, translated[2].length);
-    JsUnit.assertEquals('Public holidays', translated[2][0]);
-    JsUnit.assertEquals('not open', translated[2][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE9);
-    JsUnit.assertEquals(3, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-    JsUnit.assertEquals('10:00-14:00', translated[1][1]);
-    JsUnit.assertEquals(2, translated[2].length);
-    JsUnit.assertEquals('School holidays', translated[2][0]);
-    JsUnit.assertEquals('not open', translated[2][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE10);
-    JsUnit.assertEquals(2, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-    JsUnit.assertEquals('10:00-14:00', translated[1][1]);
-
-    // mock to always use 12-hour clock format
-    Time._is12Hour = function () { return true; };
-
-    translated = Translations.translateOpeningHours(SAMPLE1);
-    JsUnit.assertEquals(3, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat', translated[1][0]);
-    JsUnit.assertEquals(2, translated[2].length);
-    JsUnit.assertEquals('Sun', translated[2][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE2);
-    JsUnit.assertEquals(2, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE3);
-    JsUnit.assertEquals(1, translated.length);
-    JsUnit.assertEquals(1, translated[0].length);
-    JsUnit.assertEquals('From sunrise to sunset', translated[0][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE4);
-    JsUnit.assertEquals(1, translated.length);
-    JsUnit.assertEquals(1, translated[0].length);
-    JsUnit.assertEquals('Around the clock', translated[0][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE5);
-    JsUnit.assertEquals(1, translated.length);
-    JsUnit.assertEquals(1, translated[0].length);
-    JsUnit.assertEquals('Around the clock', translated[0][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE6);
-    JsUnit.assertEquals(3, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat', translated[1][0]);
-    JsUnit.assertEquals(2, translated[2].length);
-    JsUnit.assertEquals('Sun', translated[2][0]);
-    JsUnit.assertEquals('not open', translated[2][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE7);
-    JsUnit.assertEquals(2, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-
-    translated = Translations.translateOpeningHours(SAMPLE8);
-    JsUnit.assertEquals(3, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-    JsUnit.assertEquals(2, translated[2].length);
-    JsUnit.assertEquals('Public holidays', translated[2][0]);
-    JsUnit.assertEquals('not open', translated[2][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE9);
-    JsUnit.assertEquals(3, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-    JsUnit.assertEquals(2, translated[2].length);
-    JsUnit.assertEquals('School holidays', translated[2][0]);
-    JsUnit.assertEquals('not open', translated[2][1]);
-
-    translated = Translations.translateOpeningHours(SAMPLE10);
-    JsUnit.assertEquals(2, translated.length);
-    JsUnit.assertEquals(2, translated[0].length);
-    JsUnit.assertEquals('Mon-Fri', translated[0][0]);
-    JsUnit.assertEquals(2, translated[1].length);
-    JsUnit.assertEquals('Sat,Sun', translated[1][0]);
-}
+// mock to use 24-hour clock format
+Time._setIs12HourFunction(() => { return false; });
+
+let translated = Translations.translateOpeningHours(SAMPLE1);
+JsUnit.assertEquals(3, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals('09:00-18:00', translated[0][1]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat', translated[1][0]);
+JsUnit.assertEquals('10:00-15:00', translated[1][1]);
+JsUnit.assertEquals(2, translated[2].length);
+JsUnit.assertEquals('Sun', translated[2][0]);
+JsUnit.assertEquals('12:00-15:00', translated[2][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE2);
+JsUnit.assertEquals(2, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+JsUnit.assertEquals('10:00-14:00', translated[1][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE3);
+JsUnit.assertEquals(1, translated.length);
+JsUnit.assertEquals(1, translated[0].length);
+JsUnit.assertEquals('From sunrise to sunset', translated[0][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE4);
+JsUnit.assertEquals(1, translated.length);
+JsUnit.assertEquals(1, translated[0].length);
+JsUnit.assertEquals('Around the clock', translated[0][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE5);
+JsUnit.assertEquals(1, translated.length);
+JsUnit.assertEquals(1, translated[0].length);
+JsUnit.assertEquals('Around the clock', translated[0][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE6);
+JsUnit.assertEquals(3, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals('09:00-18:00', translated[0][1]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat', translated[1][0]);
+JsUnit.assertEquals('10:00-15:00', translated[1][1]);
+JsUnit.assertEquals(2, translated[2].length);
+JsUnit.assertEquals('Sun', translated[2][0]);
+JsUnit.assertEquals('not open', translated[2][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE7);
+JsUnit.assertEquals(2, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+JsUnit.assertEquals('10:00-14:00', translated[1][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE8);
+JsUnit.assertEquals(3, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+JsUnit.assertEquals('10:00-14:00', translated[1][1]);
+JsUnit.assertEquals(2, translated[2].length);
+JsUnit.assertEquals('Public holidays', translated[2][0]);
+JsUnit.assertEquals('not open', translated[2][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE9);
+JsUnit.assertEquals(3, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+JsUnit.assertEquals('10:00-14:00', translated[1][1]);
+JsUnit.assertEquals(2, translated[2].length);
+JsUnit.assertEquals('School holidays', translated[2][0]);
+JsUnit.assertEquals('not open', translated[2][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE10);
+JsUnit.assertEquals(2, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals('09:00-12:00, 13:00-18:00', translated[0][1]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+JsUnit.assertEquals('10:00-14:00', translated[1][1]);
+
+// mock to always use 12-hour clock format
+Time._setIs12HourFunction(() => { return true; });
+
+translated = Translations.translateOpeningHours(SAMPLE1);
+JsUnit.assertEquals(3, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat', translated[1][0]);
+JsUnit.assertEquals(2, translated[2].length);
+JsUnit.assertEquals('Sun', translated[2][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE2);
+JsUnit.assertEquals(2, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE3);
+JsUnit.assertEquals(1, translated.length);
+JsUnit.assertEquals(1, translated[0].length);
+JsUnit.assertEquals('From sunrise to sunset', translated[0][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE4);
+JsUnit.assertEquals(1, translated.length);
+JsUnit.assertEquals(1, translated[0].length);
+JsUnit.assertEquals('Around the clock', translated[0][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE5);
+JsUnit.assertEquals(1, translated.length);
+JsUnit.assertEquals(1, translated[0].length);
+JsUnit.assertEquals('Around the clock', translated[0][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE6);
+JsUnit.assertEquals(3, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat', translated[1][0]);
+JsUnit.assertEquals(2, translated[2].length);
+JsUnit.assertEquals('Sun', translated[2][0]);
+JsUnit.assertEquals('not open', translated[2][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE7);
+JsUnit.assertEquals(2, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+
+translated = Translations.translateOpeningHours(SAMPLE8);
+JsUnit.assertEquals(3, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+JsUnit.assertEquals(2, translated[2].length);
+JsUnit.assertEquals('Public holidays', translated[2][0]);
+JsUnit.assertEquals('not open', translated[2][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE9);
+JsUnit.assertEquals(3, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+JsUnit.assertEquals(2, translated[2].length);
+JsUnit.assertEquals('School holidays', translated[2][0]);
+JsUnit.assertEquals('not open', translated[2][1]);
+
+translated = Translations.translateOpeningHours(SAMPLE10);
+JsUnit.assertEquals(2, translated.length);
+JsUnit.assertEquals(2, translated[0].length);
+JsUnit.assertEquals('Mon-Fri', translated[0][0]);
+JsUnit.assertEquals(2, translated[1].length);
+JsUnit.assertEquals('Sat,Sun', translated[1][0]);
+
diff --git a/tests/urisTest.js b/tests/urisTest.js
index 4c08bfb8..f5fe6e86 100644
--- a/tests/urisTest.js
+++ b/tests/urisTest.js
@@ -19,23 +19,17 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-pkg.require({ 'Gdk': '3.0',
-              'Gtk': '3.0',
-              'Soup': '2.4' });
+import 'gi://Gdk?version=3.0';
+import 'gi://Gtk?version=3.0';
+import 'gi://Soup?version=2.4';
 
 const JsUnit = imports.jsUnit;
 
-const URIS = imports.uris;
+import * as URIS from './uris.js';
 
 const OSM_COORD_URL1 =
     'https://www.openstreetmap.org/?lat=39.9882&lon=-78.2409&zoom=14&layers=B000FTF';
 
-function main() {
-    parseAsObjectURLTest();
-    parseAsCoordinateURLTest();
-    parseMapsURITest();
-}
-
 function parseAsObjectURLTest() {
     _assertArrayEquals([], URIS.parseAsObjectURL('https://www.example.com'));
     _assertArrayEquals([], URIS.parseAsObjectURL('https://www.openstreet.org/'));
@@ -81,3 +75,7 @@ function _assertArrayEquals(arr1, arr2) {
     }
 }
 
+parseAsObjectURLTest();
+parseAsCoordinateURLTest();
+parseMapsURITest();
+
diff --git a/tests/utilsTest.js b/tests/utilsTest.js
index 190b3247..af3719e0 100644
--- a/tests/utilsTest.js
+++ b/tests/utilsTest.js
@@ -19,38 +19,37 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-pkg.require({ 'Gdk': '3.0',
-              'Gtk': '3.0' });
-pkg.initFormat();
+import 'gi://Gdk?version=3.0';
+import 'gi://Gtk?version=3.0';
+
+import GeocodeGlib from 'gi://GeocodeGlib';
+import GLib from 'gi://GLib';
 
-const Geocode = imports.gi.GeocodeGlib;
-const GLib = imports.gi.GLib;
+import * as Utils from './utils.js';
 
 const JsUnit = imports.jsUnit;
 
-const Utils = imports.utils;
-
-function main() {
-    osmTypeToStringTest();
-    dashedToCamelCaseTest();
-    getAccuracyDescriptionTest();
-    prettyTimeTest();
-    prettyDistanceTest();
-    prettyPopulationTest();
-    normalizeStringTest();
-    validWebsiteTest();
-    validEmailTest();
-    firstToLocaleUpperCaseTest();
-    splitAtFirstTest();
-}
+pkg.initFormat();
+
+osmTypeToStringTest();
+dashedToCamelCaseTest();
+getAccuracyDescriptionTest();
+prettyTimeTest();
+prettyDistanceTest();
+prettyPopulationTest();
+normalizeStringTest();
+validWebsiteTest();
+validEmailTest();
+firstToLocaleUpperCaseTest();
+splitAtFirstTest();
 
 function osmTypeToStringTest() {
     JsUnit.assertEquals('OSM type node', 'node',
-                        Utils.osmTypeToString(Geocode.PlaceOsmType.NODE));
+                        Utils.osmTypeToString(GeocodeGlib.PlaceOsmType.NODE));
     JsUnit.assertEquals('OSM type way', 'way',
-                        Utils.osmTypeToString(Geocode.PlaceOsmType.WAY));
+                        Utils.osmTypeToString(GeocodeGlib.PlaceOsmType.WAY));
     JsUnit.assertEquals('OSM type relation', 'relation',
-                        Utils.osmTypeToString(Geocode.PlaceOsmType.RELATION));
+                        Utils.osmTypeToString(GeocodeGlib.PlaceOsmType.RELATION));
 }
 
 function dashedToCamelCaseTest() {
@@ -60,7 +59,7 @@ function dashedToCamelCaseTest() {
 
 function getAccuracyDescriptionTest() {
     JsUnit.assertEquals('Unknown',
-                        Utils.getAccuracyDescription(Geocode.LOCATION_ACCURACY_UNKNOWN));
+                        Utils.getAccuracyDescription(GeocodeGlib.LOCATION_ACCURACY_UNKNOWN));
     JsUnit.assertEquals('Exact', Utils.getAccuracyDescription(0));
     // for other distances, the same as prettyDistance()
     JsUnit.assertEquals(Utils.prettyDistance(100),
@@ -82,16 +81,16 @@ function prettyTimeTest() {
 }
 
 function prettyDistanceTest() {
-    // tests with metric system, using override mock function
-    Utils.getMeasurementSystem = function() { return Utils.METRIC_SYSTEM; };
+    // tests with metric system
+    Utils._setMeasurementSystem(Utils.METRIC_SYSTEM);
     JsUnit.assertEquals('1 km', Utils.prettyDistance(1000, false));
     JsUnit.assertEquals('2.4 km', Utils.prettyDistance(2400, false));
     JsUnit.assertEquals('123 m', Utils.prettyDistance(123, false));
     JsUnit.assertEquals('1 km', Utils.prettyDistance(1001, false));
     JsUnit.assertEquals('1,001 m', Utils.prettyDistance(1001, true));
 
-    // tests with imperial system, using override mock function
-    Utils.getMeasurementSystem = function() { return Utils.IMPERIAL_SYSTEM; };
+    // tests with imperial system
+    Utils._setMeasurementSystem(Utils.IMPERIAL_SYSTEM);
     JsUnit.assertEquals('1 mi', Utils.prettyDistance(1609, false));
     JsUnit.assertEquals('2.4 mi', Utils.prettyDistance(3900, false));
     JsUnit.assertEquals('0.3 mi', Utils.prettyDistance(440, false));
@@ -150,3 +149,4 @@ function splitAtFirstTest() {
     _assertPair('q', 'Query=more', Utils.splitAtFirst('q=Query=more', '='));
     JsUnit.assertEquals(1, Utils.splitAtFirst('noseparator', '=').length);
 }
+
diff --git a/tests/wikipediaTest.js b/tests/wikipediaTest.js
index 145c3cfa..72d55178 100644
--- a/tests/wikipediaTest.js
+++ b/tests/wikipediaTest.js
@@ -18,27 +18,23 @@
  *
  * Author: Marcus Lundblad <ml update uu se>
  */
-const JsUnit = imports.jsUnit;
 
-pkg.require({ 'Gdk':  '3.0',
-              'Gtk':  '3.0',
-              'Soup': '2.4' });
+import 'gi://Gdk?version=3.0';
+import 'gi://Gtk?version=3.0';
+import 'gi://Soup?version=2.4';
+
+import * as Wikipedia from './wikipedia.js';
 
-const Wikipedia = imports.wikipedia;
+const JsUnit = imports.jsUnit;
 
-function main() {
-    isValidWikipediaTest();
-}
 
-function isValidWikipediaTest() {
-    // valid references
-    JsUnit.assertTrue(Wikipedia.isValidWikipedia('en:Test article'));
-    JsUnit.assertTrue(Wikipedia.isValidWikipedia('en:Test article:with colon'));
-    JsUnit.assertTrue(Wikipedia.isValidWikipedia('arz:ويكيبيديا مصرى'));
-    JsUnit.assertTrue(Wikipedia.isValidWikipedia('simple:Article'));
-    JsUnit.assertTrue(Wikipedia.isValidWikipedia('zh-yue:粵文維基百科'));
+// valid references
+JsUnit.assertTrue(Wikipedia.isValidWikipedia('en:Test article'));
+JsUnit.assertTrue(Wikipedia.isValidWikipedia('en:Test article:with colon'));
+JsUnit.assertTrue(Wikipedia.isValidWikipedia('arz:ويكيبيديا مصرى'));
+JsUnit.assertTrue(Wikipedia.isValidWikipedia('simple:Article'));
+JsUnit.assertTrue(Wikipedia.isValidWikipedia('zh-yue:粵文維基百科'));
 
-    // invalid references
-    JsUnit.assertFalse(Wikipedia.isValidWikipedia('https://en.wikipedia.org/wiki/Article'));
-    JsUnit.assertFalse(Wikipedia.isValidWikipedia('Article with no edition'));
-}
+// invalid references
+JsUnit.assertFalse(Wikipedia.isValidWikipedia('https://en.wikipedia.org/wiki/Article'));
+JsUnit.assertFalse(Wikipedia.isValidWikipedia('Article with no edition'));


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