@tsmodule/tsmodule 8.1.0
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/LICENSE +21 -0
- package/README.md +136 -0
- package/dist/commands/build/index.d.ts +7 -0
- package/dist/commands/build/index.js +3 -0
- package/dist/commands/build/lib/emitTsDeclarations.d.ts +1 -0
- package/dist/commands/build/lib/emitTsDeclarations.js +3 -0
- package/dist/commands/create/index.d.ts +1 -0
- package/dist/commands/create/index.js +1 -0
- package/dist/commands/execute/index.d.ts +1 -0
- package/dist/commands/execute/index.js +1 -0
- package/dist/commands/normalize/index.d.ts +19 -0
- package/dist/commands/normalize/index.js +2 -0
- package/dist/commands/normalize/lib/typescriptApi.d.ts +13 -0
- package/dist/commands/normalize/lib/typescriptApi.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/loader/index.d.ts +11 -0
- package/dist/loader/index.js +1 -0
- package/dist/loader/types.d.ts +22 -0
- package/dist/loader/types.js +0 -0
- package/dist/package.json +3 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/index.d.ts +27 -0
- package/dist/utils/index.js +1 -0
- package/package.json +80 -0
- package/template/.eslintrc +52 -0
- package/template/.github/workflows/ci.yml +30 -0
- package/template/.gitignore +10 -0
- package/template/README.md +5 -0
- package/template/package.json +32 -0
- package/template/src/index.ts +4 -0
- package/template/test/example.test.ts +7 -0
- package/template/tsconfig.json +41 -0
package/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) C. Lewis <ctj.lewis@icloud.com> (ctjlewis.com)
|
4
|
+
Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
7
|
+
this software and associated documentation files (the "Software"), to deal in
|
8
|
+
the Software without restriction, including without limitation the rights to
|
9
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
10
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
11
|
+
subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
18
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
19
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
20
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
21
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<h1><code>tsmodule</code></h1>
|
3
|
+
<h3>TypeScript Module Toolkit</h3>
|
4
|
+
</div>
|
5
|
+
|
6
|
+
## Features
|
7
|
+
|
8
|
+
### Quickly create TypeScript projects with **`tsmodule create`**
|
9
|
+
|
10
|
+
Supports React via TSX/JSX. Ready with zero config:
|
11
|
+
|
12
|
+
- package.json scripts: `yarn build`, `yarn test`, `yarn lint`
|
13
|
+
- ESLint, `typescript-eslint`, TypeScript configs
|
14
|
+
- CI/CD with GitHub Actions
|
15
|
+
|
16
|
+
### Build TypeScript to pure ESM with **`tsmodule build`**
|
17
|
+
|
18
|
+
- No more polyfilling to CJS or older featuresets
|
19
|
+
- Use latest syntax in source, leave backporting to downstream consumers
|
20
|
+
|
21
|
+
### Run TypeScript directly with **`tsmodule <file>`**
|
22
|
+
|
23
|
+
- Uses Node module loader to resolve TS at runtime
|
24
|
+
- Executable TypeScript files with `#!/usr/bin/env tsm`
|
25
|
+
|
26
|
+
## Use Cases
|
27
|
+
|
28
|
+
Below are some example use cases of TS modules in practice.
|
29
|
+
|
30
|
+
### Generic TypeScript library
|
31
|
+
|
32
|
+
The most common type of library will be a TS module with generic TypeScript
|
33
|
+
exports in `src/**/index.ts`, e.g.
|
34
|
+
[`await-shell`](https://github.com/ctjlewis/await-shell), a Promise wrapper
|
35
|
+
around `child_process.spawn` that's used in tsmodule itself.
|
36
|
+
|
37
|
+
This library contains only one export at `src/index.ts`, a function called
|
38
|
+
`shell`. It has one test at `test/errors.test.ts`.
|
39
|
+
|
40
|
+
### Next.js component library
|
41
|
+
|
42
|
+
It's often necessary to compile libraries of TSX components to valid JS that can
|
43
|
+
be consumed by a bundler downstream. This is handled by tsmodule out of the
|
44
|
+
box.
|
45
|
+
|
46
|
+
The following configuration can be used to export a library of TSX components in
|
47
|
+
`src/components/**/index.tsx` that is also consumed in a Next.js demo from pages
|
48
|
+
in `src/pages`:
|
49
|
+
|
50
|
+
- In `next.config.js`, allow for ESM externals (our exported components will be
|
51
|
+
ESM):
|
52
|
+
|
53
|
+
```js
|
54
|
+
{
|
55
|
+
experiments: {
|
56
|
+
esmExternals: true
|
57
|
+
}
|
58
|
+
}
|
59
|
+
```
|
60
|
+
|
61
|
+
- In package.json, configure the package to export from `dist/components`:
|
62
|
+
|
63
|
+
```json
|
64
|
+
{
|
65
|
+
"exports": {
|
66
|
+
".": "./dist/index.js",
|
67
|
+
"./*": "./dist/components/*/index.js",
|
68
|
+
"./styles": "./dist/styles/index.css",
|
69
|
+
"./styles/*": "./dist/styles/*/index.css",
|
70
|
+
"./package.json": "./package.json"
|
71
|
+
},
|
72
|
+
}
|
73
|
+
```
|
74
|
+
|
75
|
+
## Requirements
|
76
|
+
|
77
|
+
Because tsmodule packages are pure ESM environments, only **Node 16+** is
|
78
|
+
supported.
|
79
|
+
|
80
|
+
## Installation
|
81
|
+
|
82
|
+
Install tsmodule in your project (or globally) to run or build your module:
|
83
|
+
|
84
|
+
```shell
|
85
|
+
yarn add @tsmodule/tsmodule
|
86
|
+
```
|
87
|
+
|
88
|
+
|
89
|
+
You can build your TypeScript module to ESM with the `build` CLI command:
|
90
|
+
|
91
|
+
```shell
|
92
|
+
tsmodule build
|
93
|
+
```
|
94
|
+
|
95
|
+
Source will be compiled from `src/` to `dist/` and will contain only
|
96
|
+
ESM-compliant import specifiers as resolved by the tsmodule loader. It can then
|
97
|
+
be executed with Node, e.g. `node dist/index.js`.
|
98
|
+
|
99
|
+
## Footnotes
|
100
|
+
|
101
|
+
### Module configuration
|
102
|
+
|
103
|
+
All packages built with `tsmodule build` are ES modules. `{ "type": "module" }`
|
104
|
+
is forced to minimize ambiguity.
|
105
|
+
|
106
|
+
`tsmodule build` also forces the following tsconfig.json values during the
|
107
|
+
type-check and declaration emit:
|
108
|
+
|
109
|
+
```json
|
110
|
+
{
|
111
|
+
"rootDir": "src/",
|
112
|
+
"outDir": "dist/",
|
113
|
+
}
|
114
|
+
```
|
115
|
+
|
116
|
+
And conditional exports in package.json will be configured like so, such that
|
117
|
+
"index modules" at e.g. `src/test/index.ts` will be available at
|
118
|
+
`my-package/test`:
|
119
|
+
|
120
|
+
```json
|
121
|
+
{
|
122
|
+
"files": ["dist/"],
|
123
|
+
"exports": {
|
124
|
+
"./package.json": "./package.json",
|
125
|
+
"./": "./dist/index.js",
|
126
|
+
"./*": "./dist/*/index.js"
|
127
|
+
},
|
128
|
+
}
|
129
|
+
```
|
130
|
+
|
131
|
+
This has no restriction on internal imports between files, only the default
|
132
|
+
configuration for how downstream consumers can import from module subpaths.
|
133
|
+
|
134
|
+
## License
|
135
|
+
|
136
|
+
MIT © [C. Lewis](https://ctjlewis.com)
|
@@ -0,0 +1,7 @@
|
|
1
|
+
export declare const bannerLog: (msg: string) => void;
|
2
|
+
/**
|
3
|
+
* Build TS to JS. This will contain incomplete specifiers like `./foo` which
|
4
|
+
* could mean many things, all of which is handled by the loader which will
|
5
|
+
* resolve them for us.
|
6
|
+
*/
|
7
|
+
export declare const build: (dev?: boolean) => Promise<void>;
|
@@ -0,0 +1,3 @@
|
|
1
|
+
import{build as d}from"esbuild";import{existsSync as h,readFileSync as k,writeFileSync as T}from"fs";import{extname as w,resolve as l}from"path";import{readFile as x,rm as F}from"fs/promises";import a from"chalk";import O from"fast-glob";import{createDebugLogger as B,log as c}from"create-debug-logger";import{isTs as N,isTsxOrJsx as g}from"../../utils/index.js";import{emitTsDeclarations as j}from"./lib/emitTsDeclarations.js";import{normalizeImportSpecifiers as E}from"../normalize/index.js";import i from"ora";const y=t=>{c(a.bgBlue(a.white(` ${t} `)))},J=async(t=!1)=>{const n=B(J);t||y("Building for production.");const s=process.cwd(),S=l(s,"package.json"),b=await x(S,"utf-8"),m={absWorkingDir:s,outbase:"src",outdir:"dist",assetNames:"[name].js",logLevel:t?"debug":"error",charset:"utf8",format:"esm",target:"esnext",minify:!t,define:{PACKAGE_JSON:b}},f=l(s,"dist");n.log("Cleaning old output:",{distDir:f}),await F(f,{force:!0,recursive:!0});const r=O.sync("src/**/*",{cwd:s}).filter(e=>w(e)!==".d.ts").map(e=>l(e)),p=r.filter(e=>N.test(e)).filter(e=>!g.test(e));n.log("Compiling TS files:",{tsFiles:p}),await d({...m,entryPoints:p.filter(e=>!e.endsWith(".d.ts"))}),i("Built TS files.").succeed();const u=r.filter(e=>g.test(e));if(n.log("Compiling TSX files:",{tsxFiles:u}),await d({...m,entryPoints:u.filter(e=>!e.endsWith(".d.ts")),jsxFactory:"createElement",banner:{js:`import { createElement } from 'react';
|
2
|
+
`}}),i("Built TSX files.").succeed(),process.env.NO_REWRITES||(await E(),i("Normalized import specifiers.").succeed(),t)||process.env.NO_DECLARATIONS)return;y("Running post-build setup."),c(`Generating type declarations.
|
3
|
+
This might take a moment.`),j(r),i(`Generated delcarations for ${r.length} files.`).succeed();let o;h("dist/package.json")?o=JSON.parse(k("dist/package.json","utf-8")):o={},o.type="module",T("dist/package.json",JSON.stringify(o,null,2)),i('Forced "type": "module" in output.').succeed(),c(a.green("Build complete."))};export{y as bannerLog,J as build};
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const emitTsDeclarations: (files: string[]) => void;
|
@@ -0,0 +1,3 @@
|
|
1
|
+
import{TS_CONFIG as m}from"../../normalize/lib/typescriptApi.js";import a from"chalk";import{createDebugLogger as g}from"create-debug-logger";import t from"typescript";const f=o=>{const r=g(f),s=t.createProgram(o,{...m,declaration:!0,noEmit:!1,emitDeclarationOnly:!0}),i=s.emit();t.getPreEmitDiagnostics(s).concat(i.diagnostics).forEach(e=>{if(e.file){const{line:n,character:l}=t.getLineAndCharacterOfPosition(e.file,e.start??0),c=t.flattenDiagnosticMessageText(e.messageText,`
|
2
|
+
`);r.log(a.red(`${e.file.fileName} (${n+1},${l+1}): ${c}`))}else r.log(a.red(t.flattenDiagnosticMessageText(e.messageText,`
|
3
|
+
`)))})};export{f as emitTsDeclarations};
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const create: (name: string) => Promise<void>;
|
@@ -0,0 +1 @@
|
|
1
|
+
import{cp as p,readFile as d,writeFile as g}from"fs/promises";import{fileURLToPath as m,URL as u}from"url";import w from"chalk";import f from"ora";import{resolve as a}from"path";import{shell as n}from"await-shell";const S=async e=>{const i=process.cwd(),t=f(`Creating new module ${w.blueBright(e)}.`).start(),o=new u("../../../template",import.meta.url);await p(m(o),a(i,e),{recursive:!0});const s=a(i,e,"package.json"),c=await d(s,"utf-8"),r=JSON.parse(c);r.name=e,await g(s,JSON.stringify(r,null,2)),t.succeed("Project created."),t.start("Installing dependencies."),process.chdir(e);const l=["@tsmodule/tsmodule","typescript","ava","eslint","@typescript-eslint/eslint-plugin","@typescript-eslint/parser"];globalThis.SHELL_OPTIONS={stdio:["ignore","ignore","inherit"]},await n(`yarn add -D ${l.join(" ")}`),t.succeed("Dependencies installed."),t.start("Initializing git."),await n("git init"),t.succeed("Git initialized.")};export{S as create};
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const execute: () => void;
|
@@ -0,0 +1 @@
|
|
1
|
+
import{URL as s}from"url";import{spawn as n}from"child_process";const a=()=>{process.env.NODE_OPTIONS="--no-warnings";const e=import.meta.url,o=new s("../../../dist/loader/index.js",e),r=["--loader",o.href,...process.argv.slice(2)];n("node",r,{stdio:"inherit"}).on("exit",process.exit)};export{a as execute};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview
|
3
|
+
* This module contains the logic for normalizing import specifiers. It must use
|
4
|
+
* fully-specified filepaths here, since the bootstrap script will compile it
|
5
|
+
* with esbuild and then use it to normalize emitted output.
|
6
|
+
*/
|
7
|
+
/**
|
8
|
+
* Matches a complete import statement, including the import keyword, as well as
|
9
|
+
* dynamic imports, requires, and export statements.
|
10
|
+
*/
|
11
|
+
export declare const generateImportPattern: (importSource: string) => RegExp;
|
12
|
+
/**
|
13
|
+
* Rewrite an import/export/require statement.
|
14
|
+
*/
|
15
|
+
export declare const rewriteImportStatement: (importStatement: string, specifierToReplace: string, specifierReplacement: string) => string;
|
16
|
+
/**
|
17
|
+
* Rewrite imports in the emitted JS to ESM-compliant paths.
|
18
|
+
*/
|
19
|
+
export declare const normalizeImportSpecifiers: (files?: string) => Promise<any>;
|
@@ -0,0 +1,2 @@
|
|
1
|
+
import{readFile as w,writeFile as $}from"fs/promises";import x from"fast-glob";import{pathToFileURL as E}from"url";import{resolve as y}from"path";import{createDebugLogger as g}from"create-debug-logger";import{getRewrittenSpecifiers as I}from"./lib/typescriptApi.js";const P=e=>{const r=`[^
|
2
|
+
\r;]*`,o=e.replace(".","\\.").replace("/","\\/"),s=`${r}["']${o}["']${r}`,t=`(import${r}from)`,i=`(import|require)${r}\\(`,n=`(export${r}from)`;return new RegExp(`(${t}|${i}|${n})${s}`,"g")},d=(e,r,o)=>{g(d).log("Rewriting import",{importStatement:e,specifierToReplace:r,specifierReplacement:o});const[,t]=e.split(/from|\(/),i=t.replace(r,o).trim();return e.replace(t,i)},R=async(e="dist/**/*.js")=>{const r=g(R),o=await x(e,{cwd:process.cwd()});r.log("Normalizing import/require specifiers:",{filesToNormalize:o});for(const s of o){const t=y(s),i=E(t).href,n=I(t);if(!n)return null;r.log("TypeScript API yielded specifiers to rewrite:",{rewrites:n});let p=await w(t,"utf8");r.group();for(const{specifierToReplace:c,specifierReplacement:a}of n){const u=P(c),l=p.match(u)??[];r.log("Replacing import statements.",{entryPointURL:i,specifierToReplace:c,specifierReplacement:a,importStatements:l});for(const m of l){r.group();const f=d(m,c,a);r.log("Performing specifier rewrite.",{entryPointURL:i,importStatement:m,rewrittenImportStatement:f}),p=p.replace(m,f),await $(t,p),r.log("Wrote output file.",{resolvedEntryPoint:t}),r.groupEnd()}}r.groupEnd()}};export{P as generateImportPattern,R as normalizeImportSpecifiers,d as rewriteImportStatement};
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import ts from "typescript";
|
2
|
+
export declare const TS_CONFIG: ts.CompilerOptions;
|
3
|
+
export declare const compilerHost: ts.CompilerHost;
|
4
|
+
interface SpecifierReplacement {
|
5
|
+
specifierToReplace: string;
|
6
|
+
specifierReplacement: string;
|
7
|
+
}
|
8
|
+
/**
|
9
|
+
* Get the rewritten specifiers for a given module. Import/export specifiers
|
10
|
+
* will be resolved ahead-of-time by the TypeScript compiler and returned.
|
11
|
+
*/
|
12
|
+
export declare const getRewrittenSpecifiers: (modulePath: string) => SpecifierReplacement[];
|
13
|
+
export {};
|
@@ -0,0 +1 @@
|
|
1
|
+
import{dirname as E,extname as v,relative as w}from"path/posix";import{createDebugLogger as N}from"create-debug-logger";import e from"typescript";const l={moduleResolution:e.ModuleResolutionKind.NodeJs,module:e.ModuleKind.ESNext,target:e.ScriptTarget.ESNext,esModuleInterop:!0,incremental:!1,noEmit:!0,rootDir:"src",outDir:"dist"},p=e.createCompilerHost(l),R=(t,o=process.cwd())=>{const{resolvedModule:r}=e.resolveModuleName(t,o,l,p);if(!r){const s=JSON.stringify({specifier:t,entryPoint:o},null,2);throw new Error(`Could not resolve module: ${s}`)}return r},x=(t,o)=>{const r=w(E(t),o);return r.startsWith(".")?r:`./${r}`},h=t=>{const o=N(h);o.log("Getting rewritten specifiers:",{modulePath:t});const{resolvedFileName:r}=R(t),s=p.getSourceFile(r,e.ScriptTarget.ESNext);if(!s)throw new Error(`Could not read source file: ${r}`);const{statements:d,fileName:u}=s,a=[];return d.forEach(n=>{const f=e.isExportDeclaration(n);if(!(e.isImportDeclaration(n)&&!n?.importClause?.isTypeOnly)&&!f)return;const{moduleSpecifier:c}=n;if(!c){if(f)return;throw new Error(`Could not find module specifier in: ${JSON.stringify(n)}`)}if(e.isStringLiteral(c)){const{text:i}=c;if(!i.startsWith(".")||v(i))return;o.log("Using TypeScript API to resolve specifier",{specifier:i});const{resolvedModule:m}=e.resolveModuleName(i,u,{...l,allowJs:!0,checkJs:!0},p);if(!m)throw new Error(`Could not resolve module: ${i}`);const{resolvedFileName:g}=m,S=x(u,g);a.push({specifierToReplace:i,specifierReplacement:S})}}),a};export{l as TS_CONFIG,p as compilerHost,h as getRewrittenSpecifiers};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
var t="@tsmodule/tsmodule",r="module",a="8.1.0",s="tsmodule/tsmodule",d="TypeScript Module loader and compiler",m="MIT",c={tsmodule:"dist/index.js"},p={".":"./dist/loader/index.js","./*":"./dist/*/index.js","./package.json":"./package.json"},l="dist/types/index.d.ts",f=[{name:"C. Lewis",email:"ctj.lewis@icloud.com",url:"https://ctjlewis.com"}],u=["dist/","template/"],v={node:">=14"},g={bootstrap:"node bootstrap.js",prebuild:"yarn bootstrap",build:"node --no-warnings --loader ./dist/loader/index.js src/index.ts build",lint:"eslint --fix src",prepare:"yarn build",test:"ava --no-worker-threads"},S={"await-shell":"^2.7.0",chalk:"^5.0.0",commander:"^8.3.0","create-debug-logger":"^1.10.1",esbuild:"^0.14.0","fast-glob":"^3.2.10",ora:"^6.0.1",react:"^17.0.2",rollup:"^2.63.0","rollup-plugin-preserve-shebang":"^1.0.1",typescript:"^4.5.5"},w={"@types/node":"17.0.8","@types/react":"17.0.38","@typescript-eslint/eslint-plugin":"^5.9.1","@typescript-eslint/parser":"^5.9.1",ava:"^4.0.1",eslint:"^8.6.0"},C=["esm","loader","typescript","loader hook","require hook","experimental-loader"],b={files:["test/**/*.test.ts"],extensions:{ts:"module"},nodeArguments:["--no-warnings","--loader=@tsmodule/tsmodule"]},n={name:t,type:r,version:a,repository:s,description:d,license:m,bin:c,exports:p,types:l,contributors:f,files:u,engines:v,scripts:g,dependencies:S,devDependencies:w,keywords:C,ava:b};import{Command as A}from"commander";import{build as E}from"./commands/build/index.js";import{create as h}from"./commands/create/index.js";import{execute as x}from"./commands/execute/index.js";import{normalizeImportSpecifiers as y}from"./commands/normalize/index.js";const o=new A;o.command("execute <file>",{isDefault:!0}).option("--d, --dev","Enable development mode").description("Run the given TS program, analogous to `node <file>`.").action(x),o.command("build").option("-d, --dev","Build development version (default: production)").description("Builds TS files to output in dist/. (default: src/**/*.{ts,tsx})").action(async({dev:i})=>await E(i)),o.command("create <name>").description("Create a new project.").action(h),o.command("normalize [files]").description(`Rewrites import specifiers in files to ESM-compliant paths.
|
3
|
+
(default: dist/**/*.js)`).action(async({files:i})=>{await y(i)}),o.command("version").description("Print the current version.").action(()=>{console.log(typeof n=="undefined"?"Cannot read version in development mode.":`v${n.version}`)}),o.parse(process.argv);
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import type { GetFormatHook as ModuleGetFormatHook, LoadHook as ModuleLoadHook, ResolveHook as ModuleResolveHook, TransformHook as ModuleTransformSourceHook } from "./types";
|
2
|
+
export declare const resolve: ModuleResolveHook;
|
3
|
+
export declare const load: ModuleLoadHook;
|
4
|
+
/**
|
5
|
+
* @deprecated As of Node 17.
|
6
|
+
*/
|
7
|
+
export declare const getFormat: ModuleGetFormatHook;
|
8
|
+
/**
|
9
|
+
* @deprecated As of Node 17.
|
10
|
+
*/
|
11
|
+
export declare const transformSource: ModuleTransformSourceHook;
|
@@ -0,0 +1 @@
|
|
1
|
+
import{extname as m,isAbsolute as U,join as F,normalize as E,resolve as S}from"path";import{fileURLToPath as w,pathToFileURL as v,URL as L}from"url";import{promises as H}from"fs";import{transform as h}from"esbuild";import{sep as M}from"path/posix";import{sep as T}from"path/win32";import{checkExtensions as k,checkTsExtensions as D,fileExists as b,isJs as G,isTs as y,MODULE_LOADERS as R}from"../utils/index.js";import{createDebugLogger as d}from"create-debug-logger";const N=async(o,r,t)=>{const{parentURL:s}=r,e=d(N);if(e.log("Resolving specifier:",{importedFromURL:s,specifier:o}),!o.startsWith(".")&&!U(o))return e.log("Using defaultResolve for named module:",{specifier:o}),t(o,r,t);const{href:l}=v(process.cwd()),{href:i}=new L(s||l);e.log("Finding import URL for",{specifier:o,baseURL:i});let n=o;o.startsWith("file://")||(U(o)?(e.log("Setting import URL to absolute specifier."),n=v(S(E(o))).href):(e.log("Setting import URL relative to baseURL."),n=new L(o,i).href),e.log("Resolved import URL:",{importedFileURL:n,importedFromURL:s}));const f=m(s??"").toLowerCase(),u=m(n).toLowerCase();if(e.log("Rewriting file extension:",{parentExtension:f,specifierExtension:u}),u){const a=n.substring(0,n.lastIndexOf(u));if(e.log("Re-resolving specifier:",{unresolvedSpecifier:a}),G.test(u)&&y.test(f)){const p=D(a);if(p)return e.log("Found JS import in TS:",{unresolvedSpecifier:a,resolvedTsSourceFile:p}),{url:p}}return b(a)?(e.log("Found file at unresolved specifier:",{unresolvedSpecifier:a}),{url:a}):t(o,r,t)}e.log("Resolving incomplete URL import to file:",{specifier:o});const c=k(n);if(c)return e.log("Resolved import URL to file:",{resolvedFile:c}),{url:c};const x=new L(F(n,"index")).href,g=k(x);return g?(e.log("Resolved import URL to index file:",{resolvedIndexFile:g}),{url:g}):t(o,r,t)},B=async(o,r,t)=>{const s=d(B);if(s.log("Loading source file:",{url:o}),!o.includes(T)&&!o.includes(M))return s.log("Using defaultLoad for named module:",{url:o}),t(o,r,t);const e=m(o),l=R[e];if(!l)return s.log("No loader found, using defaultLoad:",{url:o}),t(o,r,t);const i=w(o),n=await H.readFile(i),f=await h(n.toString(),{...l,sourcefile:i,format:"esm"});return{format:"module",source:f.code}},O=async(o,r,t)=>{const s=d(O);s.log("Getting format for source file:",{url:o});const e=m(o);return R[e]?{format:"module"}:(s.log("No loader found, using default format:",{url:o}),t(o,r,t))},j=async(o,r,t)=>{const s=d(j);s.log("Transforming source from context:",{context:r});const{url:e}=r,l=m(e),i=R[l];return i?{source:(await h(o.toString(),{...i,logLevel:"info",charset:"utf8",target:"esnext",sourcefile:r.url,format:r.format==="module"?"esm":"cjs"})).code}:(s.log("No loader found, using default transformer:",{url:e}),t(o,r,t))};export{O as getFormat,B as load,N as resolve,j as transformSource};
|
@@ -0,0 +1,22 @@
|
|
1
|
+
export declare type Promisable<T> = Promise<T> | T;
|
2
|
+
export declare type ModuleSource = string | SharedArrayBuffer | Uint8Array;
|
3
|
+
export declare type ModuleFormat = "builtin" | "commonjs" | "json" | "module" | "wasm";
|
4
|
+
export declare type ResolveHook = (specifier: string, context: {
|
5
|
+
conditions: string[];
|
6
|
+
parentURL?: string;
|
7
|
+
}, fallback: ResolveHook) => Promisable<{
|
8
|
+
url: string;
|
9
|
+
format?: ModuleFormat;
|
10
|
+
}>;
|
11
|
+
export declare type GetFormatHook = (url: string, context: object, fallback: GetFormatHook) => Promisable<{
|
12
|
+
format: ModuleFormat;
|
13
|
+
}>;
|
14
|
+
export declare type TransformHook = (source: ModuleSource, context: Record<"url" | "format", string>, fallback: TransformHook) => Promisable<{
|
15
|
+
source: ModuleSource;
|
16
|
+
}>;
|
17
|
+
export declare type LoadHook = (url: string, context: {
|
18
|
+
format?: ModuleFormat;
|
19
|
+
}, fallback: LoadHook) => Promisable<{
|
20
|
+
format: ModuleFormat;
|
21
|
+
source: ModuleSource;
|
22
|
+
}>;
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
export*from"../loader/types.js";
|
@@ -0,0 +1,27 @@
|
|
1
|
+
export declare const DEVELOPMENT_MODE: boolean;
|
2
|
+
export declare const isTs: RegExp;
|
3
|
+
export declare const isJs: RegExp;
|
4
|
+
export declare const isTsxOrJsx: RegExp;
|
5
|
+
export declare const BASE_CONFIG: {
|
6
|
+
format: string;
|
7
|
+
charset: string;
|
8
|
+
sourcemap: string;
|
9
|
+
target: string;
|
10
|
+
minify: boolean;
|
11
|
+
};
|
12
|
+
export declare type ModuleLoaders = {
|
13
|
+
[extension: string]: {
|
14
|
+
[configKey: string]: unknown;
|
15
|
+
};
|
16
|
+
};
|
17
|
+
export declare const MODULE_LOADERS: ModuleLoaders;
|
18
|
+
export declare const POSSIBLE_EXTENSIONS: string[];
|
19
|
+
/**
|
20
|
+
* Force a Unix-like path.
|
21
|
+
*/
|
22
|
+
export declare const normalizeSpecifier: (path: string) => string;
|
23
|
+
export declare const fileExists: (fileUrl: string) => string | void;
|
24
|
+
export declare const fileExistsAny: (fileUrls: string[]) => string | void;
|
25
|
+
export declare const checkTsExtensions: (specifier: string) => string | void;
|
26
|
+
export declare const checkJsExtension: (specifier: string) => string | void;
|
27
|
+
export declare const checkExtensions: (specifier: string) => string;
|
@@ -0,0 +1 @@
|
|
1
|
+
import{existsSync as i}from"fs";import{fileURLToPath as c}from"url";import{sep as p}from"path/posix";import{sep as x}from"path";const O=!1,S=/\.[mc]?tsx?(?=\?|$)/,h=/\.([mc])?js$/,L=/\.([mc])?[tj]sx$/,e={format:"esm",charset:"utf8",sourcemap:"inline",target:"node16",minify:!1},a={".mts":{...e,loader:"ts"},".jsx":{...e,loader:"jsx"},".tsx":{...e,loader:"tsx"},".cts":{...e,loader:"ts"},".ts":{...e,loader:"ts"},".json":{...e,loader:"json"}},n=Object.keys(a),M=s=>s.split(x).join(p),l=s=>{const t=c(s);if(i(t))return s},r=s=>{for(const t of s)if(l(t))return t},m=s=>{const t=n.filter(o=>o.includes("ts")).concat([".js"]);return r(t.map(o=>s+o))},f=s=>{const t=n.filter(o=>o.includes("js")).concat([".js"]);return r(t.map(o=>s+o))},y=s=>{const t=f(s);if(t)return t;const o=m(s);if(o)return o};export{e as BASE_CONFIG,O as DEVELOPMENT_MODE,a as MODULE_LOADERS,n as POSSIBLE_EXTENSIONS,y as checkExtensions,f as checkJsExtension,m as checkTsExtensions,l as fileExists,r as fileExistsAny,h as isJs,S as isTs,L as isTsxOrJsx,M as normalizeSpecifier};
|
package/package.json
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
{
|
2
|
+
"name": "@tsmodule/tsmodule",
|
3
|
+
"type": "module",
|
4
|
+
"version": "8.1.0",
|
5
|
+
"repository": "tsmodule/tsmodule",
|
6
|
+
"description": "TypeScript Module loader and compiler",
|
7
|
+
"license": "MIT",
|
8
|
+
"bin": {
|
9
|
+
"tsmodule": "dist/index.js"
|
10
|
+
},
|
11
|
+
"exports": {
|
12
|
+
".": "./dist/loader/index.js",
|
13
|
+
"./*": "./dist/*/index.js",
|
14
|
+
"./package.json": "./package.json"
|
15
|
+
},
|
16
|
+
"types": "dist/types/index.d.ts",
|
17
|
+
"contributors": [
|
18
|
+
{
|
19
|
+
"name": "C. Lewis",
|
20
|
+
"email": "ctj.lewis@icloud.com",
|
21
|
+
"url": "https://ctjlewis.com"
|
22
|
+
}
|
23
|
+
],
|
24
|
+
"files": [
|
25
|
+
"dist/",
|
26
|
+
"template/"
|
27
|
+
],
|
28
|
+
"engines": {
|
29
|
+
"node": ">=14"
|
30
|
+
},
|
31
|
+
"scripts": {
|
32
|
+
"bootstrap": "node bootstrap.js",
|
33
|
+
"prebuild": "yarn bootstrap",
|
34
|
+
"build": "node --no-warnings --loader ./dist/loader/index.js src/index.ts build",
|
35
|
+
"lint": "eslint --fix src",
|
36
|
+
"prepare": "yarn build",
|
37
|
+
"test": "ava --no-worker-threads"
|
38
|
+
},
|
39
|
+
"dependencies": {
|
40
|
+
"await-shell": "^2.7.0",
|
41
|
+
"chalk": "^5.0.0",
|
42
|
+
"commander": "^8.3.0",
|
43
|
+
"create-debug-logger": "^1.10.1",
|
44
|
+
"esbuild": "^0.14.0",
|
45
|
+
"fast-glob": "^3.2.10",
|
46
|
+
"ora": "^6.0.1",
|
47
|
+
"react": "^17.0.2",
|
48
|
+
"rollup": "^2.63.0",
|
49
|
+
"rollup-plugin-preserve-shebang": "^1.0.1",
|
50
|
+
"typescript": "^4.5.5"
|
51
|
+
},
|
52
|
+
"devDependencies": {
|
53
|
+
"@types/node": "17.0.8",
|
54
|
+
"@types/react": "17.0.38",
|
55
|
+
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
56
|
+
"@typescript-eslint/parser": "^5.9.1",
|
57
|
+
"ava": "^4.0.1",
|
58
|
+
"eslint": "^8.6.0"
|
59
|
+
},
|
60
|
+
"keywords": [
|
61
|
+
"esm",
|
62
|
+
"loader",
|
63
|
+
"typescript",
|
64
|
+
"loader hook",
|
65
|
+
"require hook",
|
66
|
+
"experimental-loader"
|
67
|
+
],
|
68
|
+
"ava": {
|
69
|
+
"files": [
|
70
|
+
"test/**/*.test.ts"
|
71
|
+
],
|
72
|
+
"extensions": {
|
73
|
+
"ts": "module"
|
74
|
+
},
|
75
|
+
"nodeArguments": [
|
76
|
+
"--no-warnings",
|
77
|
+
"--loader=@tsmodule/tsmodule"
|
78
|
+
]
|
79
|
+
}
|
80
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
{
|
2
|
+
"extends": [
|
3
|
+
"plugin:@typescript-eslint/recommended"
|
4
|
+
],
|
5
|
+
"parser": "@typescript-eslint/parser",
|
6
|
+
"plugins": ["@typescript-eslint"],
|
7
|
+
"rules": {
|
8
|
+
|
9
|
+
"no-console": "error",
|
10
|
+
"no-trailing-spaces": "error",
|
11
|
+
"max-len": [1, 80, 2, {
|
12
|
+
"ignorePattern": "^import\\s.+\\sfrom\\s.+;$",
|
13
|
+
"ignoreUrls": true,
|
14
|
+
"ignoreStrings": true,
|
15
|
+
"ignoreTemplateLiterals": true,
|
16
|
+
"ignoreRegExpLiterals": true
|
17
|
+
}],
|
18
|
+
|
19
|
+
"@typescript-eslint/type-annotation-spacing": ["error"],
|
20
|
+
|
21
|
+
"@typescript-eslint/ban-ts-comment": [
|
22
|
+
"error",
|
23
|
+
{
|
24
|
+
"ts-nocheck": "allow-with-description",
|
25
|
+
"ts-ignore": "allow-with-description"
|
26
|
+
}
|
27
|
+
],
|
28
|
+
|
29
|
+
"indent": "off",
|
30
|
+
"@typescript-eslint/indent": ["error", 2],
|
31
|
+
|
32
|
+
"semi": "off",
|
33
|
+
"@typescript-eslint/semi": ["error", "always"],
|
34
|
+
|
35
|
+
"quotes": "off",
|
36
|
+
"@typescript-eslint/quotes": ["error", "double"],
|
37
|
+
|
38
|
+
"object-curly-spacing": "off",
|
39
|
+
"@typescript-eslint/object-curly-spacing": ["error", "always"],
|
40
|
+
|
41
|
+
"sort-imports": [
|
42
|
+
"warn",
|
43
|
+
{
|
44
|
+
"ignoreCase": false,
|
45
|
+
"ignoreDeclarationSort": false,
|
46
|
+
"ignoreMemberSort": true,
|
47
|
+
"memberSyntaxSortOrder": ["none", "all", "multiple", "single"],
|
48
|
+
"allowSeparatedGroups": true
|
49
|
+
}
|
50
|
+
]
|
51
|
+
}
|
52
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- '**'
|
7
|
+
pull_request:
|
8
|
+
branches:
|
9
|
+
- '**'
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
name: Node.js v${{ matrix.nodejs }} (${{ matrix.os }})
|
14
|
+
runs-on: ${{ matrix.os }}
|
15
|
+
timeout-minutes: 5
|
16
|
+
strategy:
|
17
|
+
matrix:
|
18
|
+
nodejs: [16]
|
19
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
20
|
+
steps:
|
21
|
+
- uses: actions/checkout@v2
|
22
|
+
- uses: actions/setup-node@v2
|
23
|
+
with:
|
24
|
+
node-version: ${{ matrix.nodejs }}
|
25
|
+
|
26
|
+
- name: Install and link
|
27
|
+
run: yarn install --frozen-lockfile && yarn build
|
28
|
+
|
29
|
+
- name: Test
|
30
|
+
run: yarn test
|
@@ -0,0 +1,32 @@
|
|
1
|
+
{
|
2
|
+
"name": "template",
|
3
|
+
"type": "module",
|
4
|
+
"version": "0.0.1",
|
5
|
+
"license": "MIT",
|
6
|
+
"types": "dist/index.d.ts",
|
7
|
+
"files": [
|
8
|
+
"dist"
|
9
|
+
],
|
10
|
+
"exports": {
|
11
|
+
"./package.json": "./package.json",
|
12
|
+
".": "./dist/index.js",
|
13
|
+
"./*": "./dist/*/index.js"
|
14
|
+
},
|
15
|
+
"scripts": {
|
16
|
+
"build": "tsmodule build",
|
17
|
+
"test": "ava",
|
18
|
+
"lint": "eslint src --fix"
|
19
|
+
},
|
20
|
+
"ava": {
|
21
|
+
"files": [
|
22
|
+
"test/**/*.test.ts"
|
23
|
+
],
|
24
|
+
"extensions": {
|
25
|
+
"ts": "module"
|
26
|
+
},
|
27
|
+
"nodeArguments": [
|
28
|
+
"--no-warnings",
|
29
|
+
"--loader=@tsmodule/tsmodule"
|
30
|
+
]
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
"include": [
|
3
|
+
"*env.d.ts",
|
4
|
+
"src/**/*"
|
5
|
+
],
|
6
|
+
"exclude": [
|
7
|
+
"node_modules",
|
8
|
+
"test/**"
|
9
|
+
],
|
10
|
+
"compilerOptions": {
|
11
|
+
"moduleResolution": "Node",
|
12
|
+
"target": "ESNext",
|
13
|
+
"module": "ESNext",
|
14
|
+
"lib": [
|
15
|
+
"DOM",
|
16
|
+
"DOM.Iterable",
|
17
|
+
"ESNext"
|
18
|
+
],
|
19
|
+
"jsx": "preserve",
|
20
|
+
"rootDir": "src",
|
21
|
+
"outDir": "dist",
|
22
|
+
"allowJs": true,
|
23
|
+
"importHelpers": true,
|
24
|
+
"esModuleInterop": true,
|
25
|
+
"allowSyntheticDefaultImports": true,
|
26
|
+
"strict": true,
|
27
|
+
"noUnusedLocals": true,
|
28
|
+
"noUnusedParameters": true,
|
29
|
+
"noImplicitReturns": true,
|
30
|
+
"noFallthroughCasesInSwitch": true,
|
31
|
+
"skipLibCheck": true,
|
32
|
+
"resolveJsonModule": true,
|
33
|
+
"declaration": true,
|
34
|
+
"sourceMap": true,
|
35
|
+
"checkJs": true,
|
36
|
+
"noEmit": false,
|
37
|
+
"forceConsistentCasingInFileNames": true,
|
38
|
+
"isolatedModules": true,
|
39
|
+
"incremental": false
|
40
|
+
}
|
41
|
+
}
|