Module assignment pragma

Module assignment pragma

Syntax

ModuleAssignmentPragma : module = StringLiteral

Semantics

The interpretation of the module = "..." pragma is host defined.

A host may treat the StringLiteral nonterminal symbol as a directory name called base, conforming to the File System Standard, using the FileSystemModulePragma semantics.

The FileSystemModulePragma semantics preludes the behavior of module resolution as follows:

  • Let pragmaDirectory be the parent directory of the source file that uses the module "..."; pragma.
  • Let modulePath be the resolution's module path.
  • If modulePath is not equals base or does not start with base + (path separator)
    • Return fallbackModuleResolution(base)
  • If the enclosing program is in a parent directory of pragmaDirectory
    • Return fallbackModuleResolution(base)
  • Return the module resolution of pragmaDirectory + (path separator) + (modulePath minus the leading component)

Example

Given an entry point that is found at the root of a source tree, being the src directory, you may write a module pragma at the top of the program:

module = "demo";

This can be useful when you have imports such as:

import type { FarAway } from "../../../somewhat/FarAway.js";

Considering somewhat is the src/somewhat directory, the above can be rewritten as:

import type { FarAway } from "demo/somewhat/FarAway.js";

Prior art

TypeScript configuration files support a paths property used for defining virtual module paths, such as in:

tsconfig.json

{
    "compilerOptions": {
        "paths": {
            "demo": ["./src"]
        }
    }
}

This configuration allows for a source file within the TypeScript project to import another source file in the same project using an absolute module path.

import calculate from "demo/util/calculate";

which causes the surrounding program and source files under the same directory

From a pure TC39 perspective there is no notion in the spec or a folder/directory.

The semantics of the specifier string are a "host" detail. The modules can all be in memory with my location, or URLs, or file paths or UUIDs. Depending on what the host has chosen.

Right, I should formulate this to be more host defined. The expectation is that engines will treat it according to file system.

@aclaymore Well, how is it now?

I've remindered declare module is already a syntax in TypeScript.

Anyway, I've been trying to inspire myself on E4X and got a more interesting syntax for us:

this module = "demo";

It reminds one of default xml namespace = "..."


Nevermind, I used this instead:

module = "demo";

so what happens when i make a malicious module that does this module = "react"?

I might be missing an important difference, but it sounds like GitHub - WICG/import-maps: How to control the behavior of JavaScript imports are already a solution for exactly this?

In case the steps I've given only affect the source tree of the program that uses module = "...".

I gave a little look there now and saw it's limited to the entry point project (i.e. you can only specify the import maps for the entry point, not within a specific library).

That still allows any transitively imported module to potentially "claim" being something else.

What would define a library from the web's perspective? Since specifiers are entirely a host concept, I believe the solution should remain entirely in the reason of the host and not involve any JS syntax. The JS ecosystem seem to be heading towards using the imports field in package.json. Bundlers and similar tools will usually rewrite import specifiers, or generate the top level import map for you, and these tools should support that imports field.

2 Likes

That seems good to me!