Skip to content

Jac Client Import Patterns - Implementation Status#

This document provides a comprehensive reference of all JavaScript/ECMAScript import patterns and their Jac equivalents, showing which patterns are currently supported.

Import Pattern Support Matrix#

Category JavaScript Pattern Jac Pattern Status Generated JavaScript Notes
Category 1: Named Imports
Single named import { useState } from 'react' cl import from react { useState } ✅ Working import { useState } from "react";
Multiple named import { map, filter } from 'lodash' cl import from lodash { map, filter } ✅ Working import { map, filter } from "lodash";
Named with alias import { get as httpGet } from 'axios' cl import from axios { get as httpGet } ✅ Working import { get as httpGet } from "axios";
Mixed named + aliases import { createApp, ref as reactive } from 'vue' cl import from vue { createApp, ref as reactive } ✅ Working import { createApp, ref as reactive } from "vue";
Category 1: Relative Paths
Single dot (current) import { helper } from './utils' cl import from .utils { helper } ✅ Working import { helper } from "./utils";
Double dot (parent) import { format } from '../lib' cl import from ..lib { format } ✅ Working import { format } from "../lib";
Triple dot (grandparent) import { settings } from '../../config' cl import from ...config { settings } ✅ Working import { settings } from "../../config"; Supports any number of dots
Category 1: Module Prefix
With jac: prefix import { renderJsxTree } from 'jac:client_runtime' cl import from jac:client_runtime { renderJsxTree } ✅ Working import { renderJsxTree } from "client_runtime"; Prefix stripped for resolution
Category 1: String Literal Imports
Hyphenated packages import { render } from 'react-dom' cl import from "react-dom" { render } ✅ Working import { render } from "react-dom"; Use string literals for package names with hyphens
Multiple hyphens import { BrowserRouter } from 'react-router-dom' cl import from "react-router-dom" { BrowserRouter } ✅ Working import { BrowserRouter } from "react-router-dom"; Works with any special characters
Category 2: Default Imports
Default import import React from 'react' cl import from react { default as React } ✅ Working import React from "react"; Must use cl prefix
Default with relative import Component from './Button' cl import from .Button { default as Component } ✅ Working import Component from "./Button";
Category 4: Namespace Imports
Namespace import import * as React from 'react' cl import from react { * as React } ✅ Working import * as React from "react"; Must use cl prefix
Namespace with relative import * as utils from './utils' cl import from .utils { * as utils } ✅ Working import * as utils from "./utils";
Category 3: Mixed Imports
Default + Named import React, { useState } from 'react' cl import from react { default as React, useState } ✅ Working import React, { useState } from "react"; Order matters: default first
Default + Namespace import React, * as All from 'react' cl import from react { default as React, * as All } ✅ Working import React, * as All from "react"; Valid JS (rarely used)
Named + Namespace import * as _, { map } from 'lodash' cl import from lodash { * as _, map } ⚠️ Generates import * as _, { map } from "lodash"; Invalid JavaScript - not recommended

Unsupported Patterns#

Pattern Why Not Supported Workaround
default or * in non-cl imports No Python equivalent for default/namespace exports Use cl import instead
Side-effect only imports Not yet implemented Use regular Python import for now
Dynamic imports Runtime feature, not syntax Use JavaScript directly or add to roadmap
Import assertions (JSON, CSS) Stage 3 proposal, specialized May add in future

Usage Rules#

1. Client Import Requirement#

  • Default imports (default as Name) and namespace imports (* as Name) MUST use cl prefix
  • Named imports work with or without cl prefix (but cl generates JavaScript)

2. Syntax Patterns#

# ✅ Correct Usage
cl import from react { useState }                    # Category 1: Named
cl import from react { default as React }            # Category 2: Default
cl import from react { * as React }                  # Category 4: Namespace
cl import from react { default as React, useState }  # Category 3: Mixed

# ❌ Incorrect Usage
import from react { default as React }   # Error: default requires cl
import from lodash { * as _ }            # Error: namespace requires cl
cl import from lodash { * as _, map }    # Generates invalid JS

3. String Literal Imports for Special Characters#

For package names containing special characters (hyphens, @-scopes, etc.), use string literals:

# ✅ Correct Usage - String literals for hyphenated packages
cl import from "react-dom" { render }
cl import from "styled-components" { default as styled }
cl import from "react-router-dom" { BrowserRouter, Route }
cl import from "date-fns" { format, parse }

# ❌ Incorrect Usage - Without quotes
cl import from react-dom { render }  # Error: hyphen not allowed in identifier

When to use string literals: - Package names with hyphens: react-dom, styled-components, react-router-dom, date-fns - Package names with special characters that aren't valid in identifiers - Any package name that would cause a syntax error without quotes

Note: String literals work with all import types (named, default, namespace, mixed)

4. Relative Path Conversion#

Jac uses Python-style dots for relative imports, which are automatically converted to JavaScript format:

Jac Syntax JavaScript Output Description
.utils "./utils" Current directory
..lib "../lib" Parent directory
...config "../../config" Grandparent directory
....deep "../../../deep" Great-grandparent directory

Implementation Details#

Grammar#

import_path: (NAME COLON)? (dotted_name | STRING) (KW_AS NAME)?
import_item: (KW_DEFAULT | STAR_MUL | named_ref) (KW_AS NAME)?

Type Handling#

  • Regular named imports: ModuleItem.name is Name
  • Default imports: ModuleItem.name is Token(KW_DEFAULT)
  • Namespace imports: ModuleItem.name is Token(STAR_MUL)
  • String literal imports: ModulePath.path contains a single String node

Validation#

  • pyast_gen_pass.py:
  • Logs error if default or * used without cl
  • Logs error if string literal imports used without cl (Python doesn't support string literal module names)
  • sym_tab_build_pass.py: Only alias added to symbol table for default/namespace; skips symbol creation for String paths
  • esast_gen_pass.py: Generates appropriate ImportSpecifier, ImportDefaultSpecifier, or ImportNamespaceSpecifier
  • parser.py: Handles both dotted_name (list of Names) and STRING in import paths
  • unitree.py: ModulePath.dot_path_str extracts string value from String literals

Testing#

All patterns tested and verified in: - test_js_generation.py::test_category1_named_imports_generate_correct_js - test_js_generation.py::test_category2_default_imports_generate_correct_js - test_js_generation.py::test_category4_namespace_imports_generate_correct_js - test_js_generation.py::test_hyphenated_package_imports_generate_correct_js - test_pyast_gen_pass.py::test_string_literal_import_requires_cl - test_pyast_gen_pass.py::test_string_literal_import_works_with_cl

Examples#

Full Feature Demo#

cl {
    # Named imports
    import from react { useState, useEffect, useRef }
    import from lodash { map as mapArray, filter }

    # Default imports
    import from react { default as React }
    import from axios { default as axios }

    # Namespace imports
    import from "date-fns" { * as DateFns }
    import from .utils { * as Utils }

    # String literal imports (for hyphenated packages)
    import from "react-dom" { render, hydrate }
    import from "styled-components" { default as styled }
    import from "react-router-dom" { BrowserRouter, Route }

    # Mixed imports
    import from react { default as React, useState, useEffect }

    # Relative paths
    import from .components.Button { default as Button }
    import from ..lib.helpers { formatDate }
    import from ...config.constants { API_URL }

    def MyComponent() {
        let [count, setCount] = useState(0);
        let now = DateFns.format(new Date());
        axios.get(API_URL);

        return count;
    }
}

Generated JavaScript Output#

import { useState, useEffect, useRef } from "react";
import { map as mapArray, filter } from "lodash";
import React from "react";
import axios from "axios";
import * as DateFns from "date-fns";
import * as Utils from "./utils";
import { render, hydrate } from "react-dom";
import styled from "styled-components";
import { BrowserRouter, Route } from "react-router-dom";
import React, { useState, useEffect } from "react";
import Button from "./components.Button";
import { formatDate } from "../lib.helpers";
import { API_URL } from "../../config.constants";

function MyComponent() {
  let [count, setCount] = useState(0);
  let now = DateFns.format(new Date());
  axios.get(API_URL);
  return count;
}

Status Summary#

  • Category 1 (Named Imports): Fully implemented and tested
  • Category 2 (Default Imports): Fully implemented and tested
  • Category 3 (Mixed Imports): Working for default+named and default+namespace
  • Category 4 (Namespace Imports): Fully implemented and tested
  • Relative Paths: Full support with automatic conversion
  • String Literal Imports: Full support for hyphenated package names (react-dom, styled-components, etc.)
  • ⚠️ Named + Namespace Mix: Generates but produces invalid JavaScript

Last Updated: 2025-10-23