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




commit a239493396ab98dd4cc68fec75463ab502b5e89f
Author: Marcus Lundblad <ml dfupdate se>
Date:   Tue May 3 00:02:54 2022 +0200

    WIP: port to ES6 modules

 data/ui/favorites-popover.ui            |   1 +
 data/ui/place-popover.ui                |   1 +
 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           |  34 +--
 src/transitplugins/openTripPlanner.js   | 173 ++++++++--------
 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 ++-
 133 files changed, 3489 insertions(+), 3344 deletions(-)
---
diff --git a/data/ui/favorites-popover.ui b/data/ui/favorites-popover.ui
index 7ee1bbb6..130f0a3d 100644
--- a/data/ui/favorites-popover.ui
+++ b/data/ui/favorites-popover.ui
@@ -6,6 +6,7 @@
     <property name="no_show_all">True</property>
     <property name="hexpand">False</property>
     <property name="width-request">320</property>
+    <property name="height-request">400</property>
     <style>
       <class name="maps-popover"/>
     </style>
diff --git a/data/ui/place-popover.ui b/data/ui/place-popover.ui
index e04114bb..4ec01987 100644
--- a/data/ui/place-popover.ui
+++ b/data/ui/place-popover.ui
@@ -5,6 +5,7 @@
     <property name="visible">False</property>
     <property name="hexpand">False</property>
     <property name="modal">False</property>
+    <property name="height-request">320</property>
     <style>
       <class name="maps-popover"/>
     </style>
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..6d610e72 100644
--- a/src/transitplugins/goMetro.js
+++ b/src/transitplugins/goMetro.js
@@ -25,23 +25,25 @@
  * 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 {Application} from '../application.js';
+//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 +103,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 +114,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..6edeaeaa 100644
--- a/src/transitplugins/openTripPlanner.js
+++ b/src/transitplugins/openTripPlanner.js
@@ -19,24 +19,27 @@
  * 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 +113,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 +163,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 +251,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 +276,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 +325,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 +521,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 +727,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 +1009,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 +1051,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 +1089,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 +1112,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 +1125,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 +1143,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 +1157,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]