Module property accessors

What about defining property accessors at the top level of the module?

On clients sometimes its desired to expose a simple API for updating some application state while implementation may want to update some internal values to deliver that update:

//main.mjs
const link = document.getElementById('theme-controller');
const availableThemes = [
  '/default.css',
  '/dark.css'
];

let currentTheme = '/default.css';

export set theme(newTheme) {
  if (newTheme === currentTheme) return true;
  if (availableThemes.includes(newTheme)) {
    link.href = newTheme;
    currentTheme = newTheme;

    return true;
  }

  return false;
}

//consumer.mjs
import { theme } from '/main.mjs';
theme = '/dark.css';

In aforementioned example there is no get accessor, so I'm still thinking how/why this should work:

import { theme } from '/main.mjs'; //Shouldn't this throw, because there is no getter (or exported getter)?

Considering that in es-modules bindings are live, I'd expect theme to contain a reference to the accessor property and I'd expect it to throw only when the value is read.

I have a bad gut feeling about this idea. Let's discuss?

Considering you can export theme() { if (arguments.length < 1) { return currentTheme; } currentTheme = arguments[0]; }, i'm not sure it would add a ton of value, and it feels to me like it would make code much harder to debug. The live-ness of named exports already is a source of confusion imo.

I can’t find a link but I have a vague memory of someone saying that this would go against a key invariant of JS - that accessed or writing to a variable in strict mode will never run arbitrary code. Apologies if I have made this memory up.

import { x } from 'path';

x++; // this could run arbitrary code

Property access on the other hand has had the possibility of getter/setter behavior since at least ES5.

// config.js
export const config = {
  set theme(t) { ... }
};
import { config } from 'config.js';

config.theme = "dark";

Was thinking about this. Currently module scope reminds the one of an async function. Accessors are object entities, but not scope entities. Such addition won't be in line with the language, at least as I see it.

This is indeed a bad idea. I have no arguments to defend this idea.