module-tsx 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,31 +1,30 @@
1
1
  # module-tsx
2
2
 
3
- Run TypeScript (and React) module directly in the browser.
3
+ Run TypeScript (and React) modules directly in the browser, without a build step.
4
4
 
5
- # Usage
5
+ ## Usage
6
6
 
7
7
  ```html
8
- <!-- Load This Library -->
8
+ <!-- Load this library -->
9
9
  <script type="module" src="https://esm.sh/module-tsx"></script>
10
10
 
11
11
  <div id="root"></div>
12
12
 
13
- <!-- Write Your TypeScript Module -->
13
+ <!-- Write your TypeScript/TSX inline -->
14
14
  <script type="module-tsx">
15
- import React from "react"; // <- This will be converted to https://esm.sh/react
16
- import { createRoot } from "react-dom/client"; // <- This will also be converted automatically
17
- import App from "./src/App.tsx"; // <- Your TypeScript module will also be compiled on the fly
18
- import lib from "https://my.cdn.domain"; // <- Direct http import will NOT be compiled
15
+ import React from "react"; // bare specifier https://esm.sh/react
16
+ import { createRoot } from "react-dom/client";
17
+ import App from "./src/App.tsx"; // relative imports are fetched and compiled on the fly
19
18
 
20
- const root = document.getElementById("root") as HTMLDivElement; // <- You can write TypeScript directly
19
+ const root = document.getElementById("root") as HTMLDivElement;
21
20
  createRoot(root).render(
22
21
  <React.StrictMode>
23
22
  <App />
24
23
  </React.StrictMode>
25
- // ^ You can also write JSX/TSX directly
26
24
  );
27
25
  </script>
28
- <!-- OR -->
26
+
27
+ <!-- OR load an external file -->
29
28
  <script type="module-tsx" src="./main.tsx"></script>
30
29
  ```
31
30
 
@@ -37,3 +36,72 @@ export default function App() {
37
36
  return <div>Hello, module-tsx!</div>;
38
37
  }
39
38
  ```
39
+
40
+ ## Features
41
+
42
+ - **TypeScript & JSX/TSX** — transpiled on the fly using the TypeScript compiler
43
+ - **Bare specifier resolution** — `import "react"` is automatically rewritten to a CDN URL (defaults to `https://esm.sh/`)
44
+ - **Relative imports** — `.ts`/`.tsx` files are fetched and compiled recursively
45
+ - **CSS imports** — `import "./style.css"` injects a `<style>` tag; `import "./style.module.css"` returns a CSS Modules object
46
+ - **Import map support** — respects `<script type="importmap">` on the page for specifier overrides
47
+ - **Auto React import** — JSX is detected and `import React from "react"` is injected automatically if missing
48
+
49
+ ## Programmatic API
50
+
51
+ ```ts
52
+ import { ModuleTSX } from "module-tsx";
53
+
54
+ const m = new ModuleTSX({
55
+ baseUrl: location.href, // base for resolving relative specifiers
56
+ importMap: { imports: { react: "https://esm.sh/react" } }, // merged with page importmaps
57
+ resolveBareSpecifier: "https://cdn.jsdelivr.net/npm/", // string prefix or function
58
+ });
59
+
60
+ // Import a module by specifier
61
+ const react = await m.import("react");
62
+ const app = await m.import("./app.tsx");
63
+
64
+ // Import from an in-memory string
65
+ const { x } = await m.importCode(
66
+ document.location.href,
67
+ `export const x: number = 1`,
68
+ );
69
+
70
+ // Events
71
+ m.addEventListener("import", (e) => console.log("loading", e.detail.id));
72
+ m.addEventListener("import:error", (e) =>
73
+ console.error("failed", e.detail.id, e.detail.error),
74
+ );
75
+ m.addEventListener("transform", (e) =>
76
+ console.log("compiling", e.detail.sourceUrl),
77
+ );
78
+ m.addEventListener("transform:error", (e) =>
79
+ console.error("compile error", e.detail.sourceUrl, e.detail.error),
80
+ );
81
+ ```
82
+
83
+ ## Use with AI
84
+
85
+ module-tsx is well-suited for AI-generated pages — an AI can produce a single, self-contained HTML file that runs TypeScript and React directly in the browser with no build step or configuration.
86
+
87
+ To use the skill, run
88
+
89
+ ```sh
90
+ npx skills add yieldray/module-tsx
91
+ ```
92
+
93
+ ## CDN
94
+
95
+ ```html
96
+ <!-- ESM -->
97
+ <script type="module" src="https://esm.sh/module-tsx"></script>
98
+
99
+ <!-- ESM (self-contained, no external dependencies) -->
100
+ <script
101
+ type="module"
102
+ src="https://raw.esm.sh/module-tsx/dist/index.mjs"
103
+ ></script>
104
+
105
+ <!-- UMD (exposes window.ModuleTSX) -->
106
+ <script src="https://raw.esm.sh/module-tsx/dist/index.umd.js"></script>
107
+ ```
package/dist/index.d.ts CHANGED
@@ -1,7 +1,28 @@
1
1
  //#region src/importmap.d.ts
2
- interface ImportMapData {
3
- imports?: Record<string, string>;
4
- scopes?: Record<string, Record<string, string>>;
2
+ type ModuleSpecifierMap = Map<string, URL | null>;
3
+ interface SpecifierResolutionRecord {
4
+ serializedBaseURL: string;
5
+ specifier: string;
6
+ specifierAsURL: URL | null;
7
+ }
8
+ declare class ImportMap {
9
+ imports: ModuleSpecifierMap;
10
+ scopes: Map<string, ModuleSpecifierMap>;
11
+ integrity: Map<string, string>;
12
+ constructor(imports?: ModuleSpecifierMap, scopes?: Map<string, ModuleSpecifierMap>, integrity?: Map<string, string>);
13
+ /** Parse a JSON import map string against a base URL. */
14
+ static parse(input: string, baseURL: URL | string): ImportMap;
15
+ /** Build an ImportMap from a plain object (same shape as the JSON format). */
16
+ static of(json: object, baseURL: URL | string): ImportMap;
17
+ /** Merge newImportMap into oldImportMap in place (spec § "merge existing and new import maps"). */
18
+ static merge(oldImportMap: ImportMap, newImportMap: ImportMap, resolvedModuleSet?: ReadonlyArray<SpecifierResolutionRecord>): void;
19
+ /** Resolve a specifier against an import map (spec § "resolve a module specifier"). */
20
+ static resolve(specifier: string, importMap: ImportMap, baseURL: string | URL): {
21
+ url: string;
22
+ record: SpecifierResolutionRecord;
23
+ } | undefined;
24
+ /** Parse all <script type="importmap"> elements from the DOM. */
25
+ static fromDOM(): ImportMap;
5
26
  }
6
27
  //#endregion
7
28
  //#region src/module-tsx.d.ts
@@ -12,7 +33,7 @@ interface ModuleTSXConfig {
12
33
  */
13
34
  baseUrl?: string;
14
35
  fetch?: (fullURL: string) => Promise<Response>;
15
- importMap?: ImportMapData;
36
+ importMap?: ImportMap;
16
37
  /**
17
38
  * Given a bare specifier, return a full URL to load the module.
18
39
  * This can be used to convert for example import "react" to import "https://esm.sh/react".
@@ -22,16 +43,20 @@ interface ModuleTSXConfig {
22
43
  resolveBareSpecifier?: string | ((specifier: string) => string);
23
44
  }
24
45
  interface ModuleTSXEventMap {
46
+ /** Fired when an import starts. `id` is the original specifier as passed by the caller. */
25
47
  import: CustomEvent<{
26
48
  id: string;
27
49
  }>;
50
+ /** Fired when an import fails. `id` is the specifier at the point of failure. */
28
51
  "import:error": CustomEvent<{
29
52
  id: string;
30
53
  error: any;
31
54
  }>;
55
+ /** Fired when a source file starts being transpiled. */
32
56
  transform: CustomEvent<{
33
57
  sourceUrl: string;
34
58
  }>;
59
+ /** Fired when transpilation fails. */
35
60
  "transform:error": CustomEvent<{
36
61
  sourceUrl: string;
37
62
  error: any;
@@ -39,15 +64,20 @@ interface ModuleTSXEventMap {
39
64
  }
40
65
  interface IModuleTSX extends EventTarget {
41
66
  addEventListener<T extends keyof ModuleTSXEventMap>(type: T, listener: (this: ModuleTSX, ev: ModuleTSXEventMap[T]) => any, options?: boolean | AddEventListenerOptions): void;
67
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
42
68
  }
43
69
  declare class ModuleTSX extends EventTarget implements IModuleTSX {
44
70
  readonly baseUrl: string;
45
- readonly importMap: ImportMapData;
71
+ readonly importMap: ImportMap;
46
72
  readonly fetch: (url: string) => Promise<Response>;
47
73
  readonly resolveBareSpecifier: (specifier: string) => string;
74
+ private readonly resolvedModuleSet;
48
75
  private readonly sourceTracker;
49
76
  private readonly fetchText;
50
77
  constructor(config?: ModuleTSXConfig);
78
+ /** Add a new import map, merging it into the existing one per the spec.
79
+ * Rules that conflict with already-resolved modules are silently dropped. */
80
+ addImportMap(newImportMap: ImportMap): void;
51
81
  private emit;
52
82
  import(id: string, options?: any): Promise<any>;
53
83
  importCode(sourceUrl: string, code: string, options?: any): Promise<any>;
@@ -55,6 +85,7 @@ declare class ModuleTSX extends EventTarget implements IModuleTSX {
55
85
  private transformSourceModule;
56
86
  private getLoaderByResourceType;
57
87
  private tsxLoader;
88
+ private resolveLocalUrl;
58
89
  private resolveSpecifier;
59
90
  private resolveSpecifiers;
60
91
  }
@@ -71,4 +102,4 @@ declare class ModuleTSXError extends Error {
71
102
  */
72
103
  declare const instance: ModuleTSX;
73
104
  //#endregion
74
- export { ModuleTSX, ModuleTSXError, instance };
105
+ export { ImportMap, ModuleTSX, ModuleTSXError, instance };