npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@isl-lang/import-resolver

v1.0.0

Published

ISL import resolution - resolves local module imports, detects cycles, and bundles multi-file specs

Readme

@isl-lang/import-resolver

ISL Import Resolution and Multi-File Bundling

Overview

The Import Resolver package provides functionality for resolving local module imports in ISL specifications, detecting cycles, and bundling multiple ISL files into a single AST.

Features

  • Local Module Imports: Resolve ./foo.isl and ../bar.isl style relative imports
  • Cycle Detection: Detect and report circular dependencies with clear error messages
  • Fragment Merging: Merge types, entities, behaviors, and other fragments from multiple files
  • Conflict Detection: Error on duplicate definitions (entities, types, behaviors with same name)
  • Stable Bundling: Produce deterministic bundled AST with canonical ordering
  • MVP Mode Toggle: Explicitly gate import resolution for single-file mode

Installation

npm install @isl-lang/import-resolver
# or
pnpm add @isl-lang/import-resolver

Quick Start

Multi-File Mode (Imports Enabled)

import { resolveAndBundle } from '@isl-lang/import-resolver';

const result = await resolveAndBundle('./main.isl', {
  basePath: './specs',
  enableImports: true,
});

if (result.success) {
  console.log('Bundled AST:', result.bundle);
} else {
  console.error('Errors:', result.errors);
}

Single-File Mode (MVP Mode)

import { parseSingleFile } from '@isl-lang/import-resolver';

const source = `
domain MyApp {
  version: "1.0.0"
  entity User { id: UUID }
}
`;

const result = parseSingleFile(source, 'spec.isl');

if (result.success) {
  console.log('Parsed AST:', result.bundle);
} else {
  // If the file has imports, this will fail with a clear error
  // explaining that single-file mode doesn't support imports
  console.error('Errors:', result.errors);
}

Import Rules

Supported Import Paths

Only relative paths are supported:

imports {
  User, Email from "./types.isl"       # Same directory
  Payment from "../billing/payment.isl" # Parent directory
  Config from "./config"                # Extension optional (.isl added)
}

Unsupported Import Paths

The following import paths will result in errors:

imports {
  User from "types.isl"           # ❌ Not relative (missing ./)
  User from "/absolute/path.isl"  # ❌ Absolute paths not allowed
  User from "@stdlib/auth"        # ❌ Package imports not yet supported
}

Import Items

Import specific symbols from a module:

imports {
  User from "./types.isl"                   # Single import
  User, Email, UserId from "./types.isl"    # Multiple imports
  User as AppUser from "./types.isl"        # Aliased import
}

Merge Semantics

What Gets Merged

When bundling multiple files, the following are merged:

| Fragment Type | Merge Behavior | |--------------|----------------| | Types | Deduplicated by name (conflict if same name) | | Entities | Deduplicated by name (conflict if same name) | | Behaviors | Deduplicated by name (conflict if same name) | | Invariants | Deduplicated by name (conflict if same name) | | Policies | Deduplicated by name (conflict if same name) | | Views | Deduplicated by name (conflict if same name) | | Scenarios | All merged (duplicates allowed) | | Chaos | All merged (duplicates allowed) |

Conflict Detection

By default, duplicate definitions result in errors:

[DUPLICATE_ENTITY] Duplicate entity "User" found:
  First defined in: types.isl (line 5)
  Also defined in: main.isl (line 10)

Each entity must have a unique name across all modules.

Shadowing Mode

If you need to override definitions, enable shadowing:

const result = await resolveAndBundle('./main.isl', {
  enableImports: true,
  allowShadowing: true,  // Last-write-wins
});

In shadowing mode:

  • Later definitions override earlier ones (in topological order)
  • Warnings are emitted for shadowed imports

Canonical Ordering

The bundled AST maintains canonical ordering for deterministic output:

  1. Types: Sorted alphabetically by name
  2. Entities: Sorted alphabetically by name
  3. Behaviors: Sorted alphabetically by name
  4. Invariants: Sorted alphabetically by name
  5. Policies: Sorted alphabetically by name
  6. Views: Sorted alphabetically by name
  7. Scenarios: Sorted by behavior name
  8. Chaos: Sorted by behavior name

Cycle Detection

Circular dependencies are detected and reported with clear paths:

[CIRCULAR_DEPENDENCY] Circular dependency detected:
  → /specs/a.isl
  → /specs/b.isl
  → /specs/c.isl
  → /specs/a.isl

Circular imports are not allowed.
Consider restructuring your modules to break the cycle.

Diamond Dependencies

Diamond dependencies (multiple paths to the same module) are allowed:

main.isl
├── a.isl
│   └── shared.isl
└── b.isl
    └── shared.isl

The shared module is only included once in the bundle.

MVP Mode Toggle

Checking for Imports

import { hasImports } from '@isl-lang/import-resolver';

const needsImportResolution = hasImports(source);
if (needsImportResolution) {
  // Use resolveAndBundle
} else {
  // Can use parseSingleFile
}

Single-File Mode Error

When imports are disabled and a file has imports:

[IMPORTS_DISABLED] Import resolution is disabled (single-file mode).
Cannot import "./types.isl".
To enable multi-file imports, set 'enableImports: true' in resolver options.
Note: Multi-file mode requires all imported modules to be available.

API Reference

resolveAndBundle(entryPoint, options)

Resolve imports and bundle into a single AST.

interface ResolveAndBundleOptions {
  basePath?: string;           // Base directory for imports
  enableImports?: boolean;     // Enable/disable import resolution
  allowShadowing?: boolean;    // Allow definition shadowing
  stripImports?: boolean;      // Remove import declarations from bundle
  bundleDomainName?: string;   // Custom domain name for bundle
  bundleVersion?: string;      // Custom version for bundle
  maxDepth?: number;           // Max import depth (default: 100)
}

parseSingleFile(source, filename)

Parse a single file without import resolution.

const result = parseSingleFile(source, 'spec.isl');
// Returns BundleResult

hasImports(source)

Check if source has import declarations.

const hasImports: boolean = hasImports(source);

validateImportPaths(source)

Validate import paths without resolution.

const { valid, errors } = validateImportPaths(source);

createVirtualFS(files, basePath)

Create a virtual file system for testing.

const vfs = createVirtualFS({
  'main.isl': 'domain Main { ... }',
  'types.isl': 'domain Types { ... }',
}, '/test');

Limitations

Current Limitations

  1. Only relative paths: Package imports (@stdlib/auth) not yet supported
  2. No glob imports: Cannot import { * } from "./module"
  3. No re-exports: Cannot re-export from modules
  4. No conditional imports: All imports are unconditional

Future Enhancements

  • [ ] Package/workspace imports
  • [ ] Glob imports (import * as Types from "./types")
  • [ ] Re-exports
  • [ ] Import aliases at module level
  • [ ] Lazy import resolution

Error Codes

| Code | Description | |------|-------------| | IMPORTS_DISABLED | Import resolution disabled but file has imports | | MODULE_NOT_FOUND | Import target file not found | | PARSE_ERROR | Failed to parse imported module | | READ_ERROR | Failed to read file | | CIRCULAR_DEPENDENCY | Circular import detected | | MAX_DEPTH_EXCEEDED | Import chain too deep | | DUPLICATE_TYPE | Duplicate type definition | | DUPLICATE_ENTITY | Duplicate entity definition | | DUPLICATE_BEHAVIOR | Duplicate behavior definition | | SYMBOL_NOT_FOUND | Imported symbol not exported | | INVALID_IMPORT_PATH | Import path format invalid |

Testing

# Run tests
pnpm test

# Run tests with coverage
pnpm test:coverage

# Run tests in watch mode
pnpm test:watch

License

MIT