Skip to main content

Phase 7. import-ts grammar

FieldValue
MEPMEP-72 §Phases
StatusNOT STARTED
Tracking issue(pending)
Tracking PR(pending)
Commit(pending)

Gate

TestPhase7ImportTs in parser/import_ts_test.go: subtests bare_npm, prefixed_npm, prefixed_jsr, with_alias, with_specifier_path, with_semver_range, lockfile_pinned_only, parse_errors. The first six parse representative import ts "..." as <alias> forms and assert the AST contains the expected fields. The seventh asserts that a non-pinned semver-range fails the parser unless mochi.lock is present with a pinned version. The eighth tests malformed inputs (missing semver, invalid alias, bare path without prefix, prefix without scope) and asserts each produces a clear diagnostic.

Lowering decisions

Grammar:

import_ts_stmt = "import" "ts" ts_specifier "as" identifier
ts_specifier = '"' ts_specifier_body '"'
ts_specifier_body = registry_prefix? package_ref ("@" semver)? path?
registry_prefix = "npm:" | "jsr:"
package_ref = scoped_pkg | unscoped_pkg
scoped_pkg = "@" identifier "/" identifier
unscoped_pkg = identifier
semver = semver_pinned | semver_range
semver_pinned = digit+ "." digit+ "." digit+ ("-" prerelease)?
semver_range = caret_range | tilde_range | hyphen_range | "latest" | "*"
path = "/" path_segment ("/" path_segment)*

Examples:

  • import ts "[email protected]" as z — npm package, pinned version (npm is the default registry).
  • import ts "npm:zod@^3.22" as z — npm package, explicit prefix, caret range.
  • import ts "jsr:@std/encoding@^1" as enc — JSR package, scoped, caret range.
  • import ts "jsr:@hono/hono@^4" as hono — JSR package, scoped.
  • import ts "lodash@^4.17/fp/curry" as curry — npm package, subpath import.
  • import ts "drizzle-orm@latest" as db — npm package, latest tag.

The parser recognises the import statement at the top of a Mochi file (same position as import for Mochi modules). The AST node ImportTsStmt carries {registry, scope, name, semver, subpath, alias, position}.

A semver range (not a pinned version) is allowed only when mochi.lock contains a pinned resolution for the same (registry, scope, name) triple. Lock-mode --check and lock-mode --regenerate are distinguished: --check fails on ranges without a lock entry; --regenerate resolves the range against the registry and writes a pinned entry.

The alias identifier follows Mochi's identifier rules (start with letter or underscore, ASCII alphanumeric plus underscore, no shadow of built-in names). Two import ts statements in the same file must use distinct aliases (a duplicate-alias diagnostic catches the conflict at parse time).

The phase wires the parser into MEP-52 phase 12's existing FFI surface so that the alias is in scope for the rest of the file. References to alias-namespaced functions (z.string(), hono.serve()) are bound to the corresponding extern fn declarations from phase 6's emitted shim.

Files changed

FilePurpose
parser/import_ts.goparser entry for import ts statements
parser/import_ts_test.goTestPhase7ImportTs sentinel
ast/import_ts.goImportTsStmt AST node + walker hooks
types/import_ts_binder.goalias binding into the file-level symbol table

Test set

8 subtests as listed in the Gate section.

Cross-references