@checkdigit/typescript-config 3.3.0-PR.30-3a83 → 3.3.0-PR.30-a6df

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/bin/builder.mjs CHANGED
@@ -20,26 +20,28 @@ async function getFiles(directory) {
20
20
  );
21
21
  return files.flat();
22
22
  }
23
- function setup(pluginBuild) {
24
- pluginBuild.onResolve({ filter: /.*/u }, async (resolved) => {
25
- if (resolved.kind === "entry-point" || !resolved.path.startsWith(".") || resolved.path.endsWith(".js")) {
26
- return { external: resolved.kind !== "entry-point" };
27
- }
28
- let isDirectory = false;
29
- try {
30
- const stats = await fs.lstat(path.join(resolved.resolveDir, resolved.path));
31
- isDirectory = stats.isDirectory();
32
- } catch {
33
- }
34
- let newPath = resolved.path;
35
- newPath += isDirectory ? `/index.mjs` : `.mjs`;
36
- return { path: newPath, external: true };
37
- });
23
+ function setup(type2) {
24
+ const extension = type2 === "module" ? "mjs" : "cjs";
25
+ return (pluginBuild) => {
26
+ pluginBuild.onResolve({ filter: /.*/u }, async (resolved) => {
27
+ if (resolved.kind === "entry-point" || !resolved.path.startsWith(".") || resolved.path.endsWith(".js")) {
28
+ return { external: resolved.kind !== "entry-point" };
29
+ }
30
+ let isDirectory = false;
31
+ try {
32
+ const stats = await fs.lstat(path.join(resolved.resolveDir, resolved.path));
33
+ isDirectory = stats.isDirectory();
34
+ } catch {
35
+ }
36
+ let newPath = resolved.path;
37
+ newPath += isDirectory ? `/index.${extension}` : `.${extension}`;
38
+ return { path: newPath, external: true };
39
+ });
40
+ };
38
41
  }
39
- async function builder_default({ inDir: inDir2, outDir: outDir2 }) {
42
+ async function builder_default({ type: type2, inDir: inDir2, outDir: outDir2 }) {
40
43
  const messages2 = [];
41
- const sourceDirectory = inDir2;
42
- const allSourceFiles = await getFiles(sourceDirectory);
44
+ const allSourceFiles = await getFiles(inDir2);
43
45
  const productionSourceFiles = allSourceFiles.filter(
44
46
  // && !file.endsWith('.test.ts') && !file.endsWith('.spec.ts')
45
47
  (file) => file.endsWith(".ts")
@@ -54,7 +56,10 @@ async function builder_default({ inDir: inDir2, outDir: outDir2 }) {
54
56
  outDir: outDir2
55
57
  });
56
58
  const emitResult = program.emit();
57
- const allDiagnostics = [...typescript.getPreEmitDiagnostics(program), ...emitResult.diagnostics];
59
+ const allDiagnostics = typescript.sortAndDeduplicateDiagnostics([
60
+ ...typescript.getPreEmitDiagnostics(program),
61
+ ...emitResult.diagnostics
62
+ ]);
58
63
  for (const diagnostic of allDiagnostics) {
59
64
  if (diagnostic.file) {
60
65
  assert.ok(diagnostic.start !== void 0);
@@ -66,41 +71,50 @@ async function builder_default({ inDir: inDir2, outDir: outDir2 }) {
66
71
  }
67
72
  }
68
73
  if (emitResult.emitSkipped) {
69
- throw new Error("TypeScript compilation failed");
74
+ throw new Error(`TypeScript compilation failed ${JSON.stringify(messages2)}`);
70
75
  }
71
76
  const buildResult = await build({
72
77
  entryPoints: productionSourceFiles,
73
78
  bundle: true,
74
79
  platform: "node",
75
- format: "esm",
80
+ format: type2 === "module" ? "esm" : "cjs",
76
81
  outdir: outDir2,
77
82
  sourcemap: "inline",
78
83
  sourcesContent: false,
79
- outExtension: { ".js": ".mjs" },
84
+ outExtension: { ".js": type2 === "module" ? ".mjs" : ".cjs" },
80
85
  plugins: [
81
86
  {
82
87
  name: "resolve-ts",
83
- setup
88
+ setup: setup(type2)
84
89
  }
85
90
  ]
86
91
  });
87
92
  messages2.push(...buildResult.errors.map((error) => `esbuild error: ${error.text}`));
88
93
  messages2.push(...buildResult.warnings.map((warning) => `esbuild warning: ${warning.text}`));
94
+ if (messages2.length > 0) {
95
+ throw new Error(`esbuild failed ${JSON.stringify(messages2)}`);
96
+ }
89
97
  return messages2;
90
98
  }
91
99
 
92
100
  // src/builder/index.mts
93
101
  var {
94
- values: { inDir, outDir }
102
+ values: { type, inDir, outDir }
95
103
  } = parseArgs({
96
104
  options: {
105
+ type: { type: "string", short: "t", default: "module" },
97
106
  inDir: { type: "string", short: "i", default: "src" },
98
107
  outDir: { type: "string", short: "o", default: "build" }
99
108
  }
100
109
  });
110
+ assert2.ok(type === "module" || type === "commonjs", "type must be module or commonjs");
101
111
  assert2.ok(inDir !== void 0, "inDir is required");
102
112
  assert2.ok(outDir !== void 0, "outDir is required");
103
- var messages = await builder_default({ inDir: path2.join(process.cwd(), inDir), outDir: path2.join(process.cwd(), outDir) });
113
+ var messages = await builder_default({
114
+ type,
115
+ inDir: path2.join(process.cwd(), inDir),
116
+ outDir: path2.join(process.cwd(), outDir)
117
+ });
104
118
  if (messages.length > 0) {
105
119
  console.warn(JSON.stringify(messages, void 0, 2));
106
120
  process.exit(1);
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@checkdigit/typescript-config","version":"3.3.0-PR.30-3a83","description":"Check Digit standard Typescript configuration","prettier":"@checkdigit/prettier-config","engines":{"node":">=16"},"bin":{"builder":"./bin/builder.mjs"},"peerDependencies":{"@types/node":">=16","esbuild":"0.17.18","typescript":">=5.0.4 <5.1"},"repository":{"type":"git","url":"git+https://github.com/checkdigit/typescript-config.git"},"author":"Check Digit, LLC","license":"MIT","bugs":{"url":"https://github.com/checkdigit/typescript-config/issues"},"homepage":"https://github.com/checkdigit/typescript-config#readme","scripts":{"preversion":"npm test","postversion":"git push && git push --tags","prepare":"npm run build-builder","lint:fix":"eslint -f unix --ext .ts,.mts src --fix","lint":"eslint -f unix --ext .ts,.mts src","prettier":"prettier --ignore-path .gitignore --list-different .","prettier:fix":"prettier --ignore-path .gitignore --write .","test":"npm run ci:compile && npm run ci:test && npm run ci:lint && npm run ci:style","build-builder":"esbuild src/builder/index.mts --bundle --platform=node --format=esm --external:typescript --external:esbuild --outfile=build-builder/builder.mjs && mkdir -p bin && { echo '#!/usr/bin/env node'; cat build-builder/builder.mjs; } > bin/builder.mjs && chmod +x bin/builder.mjs","build-tsc-cjs":"rimraf build-tsc-cjs && tsc --outDir build-tsc-cjs","build-esbuild-cjs":"rimraf build-esbuild-cjs && esbuild ./src/*.ts ./src/*/*.ts --platform=node --bundle --format=cjs --sourcemap=inline --sources-content=false --outdir=build-esbuild-cjs","build-esbuild-cjs-bundle":"rimraf build-esbuild-cjs-bundle && esbuild src/test/index.test.ts --bundle --platform=node --format=cjs --sourcemap=inline --sources-content=false --outfile=build-esbuild-cjs-bundle/test/index.test.cjs","build-esbuild-esm":"rimraf build-esbuild-esm && node bin/builder.mjs --outDir=build-esbuild-esm","build-esbuild-esm-bundle":"rimraf build-esbuild-esm-bundle && esbuild src/test/index.test.ts --bundle --platform=node --format=esm --sourcemap=inline --sources-content=false --outfile=build-esbuild-esm-bundle/test/index.test.mjs","test-jest-esm":"NODE_OPTIONS=\"--experimental-vm-modules\" jest --coverage=false src/*.mts src/*/*.mts src/*/*/*.mts","test-jest-cjs":"jest --coverage=false src/*.ts src/*/*.ts src/*/*/*.ts","test-tsc-cjs":"node --test build-tsc-cjs/test/index.test.js","test-esbuild-cjs":"node --test build-esbuild-cjs/test/index.test.js","test-esbuild-cjs-bundle":"node --test build-esbuild-cjs-bundle/test/index.test.cjs","test-esbuild-esm":"node --test build-esbuild-esm/test/index.test.mjs","test-esbuild-esm-bundle":"echo 'node -test build-esbuild-esm-bundle/test/index.test.mjs'","ci:test":"npm run test-jest-cjs && npm run test-jest-esm &&npm run test-tsc-cjs && npm run test-esbuild-cjs && npm run test-esbuild-cjs-bundle && npm run test-esbuild-esm && npm run test-esbuild-esm-bundle","ci:compile":"npm run build-builder && npm run build-tsc-cjs && npm run build-esbuild-cjs && npm run build-esbuild-cjs-bundle && npm run build-esbuild-esm && npm run build-esbuild-esm-bundle","ci:lint":"npm run lint","ci:style":"npm run prettier"},"devDependencies":{"@checkdigit/prettier-config":"^3.4.0","@types/debug":"^4.1.7","@types/jest":"^29.5.1","@types/uuid":"^9.0.1","@typescript-eslint/eslint-plugin":"^5.59.5","@typescript-eslint/parser":"^5.59.5","debug":"^4.3.4","eslint":"^8.40.0","eslint-config-prettier":"^8.8.0","get-port":"^6.1.2","got":"^11.8.6","jest":"^29.5.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","uuid":"^9.0.0"},"eslintConfig":{"parser":"@typescript-eslint/parser","plugins":["@typescript-eslint"],"parserOptions":{"project":"./tsconfig.json"},"extends":["eslint:all","plugin:@typescript-eslint/recommended","plugin:@typescript-eslint/recommended-requiring-type-checking","plugin:@typescript-eslint/strict","prettier"],"rules":{"@typescript-eslint/non-nullable-type-assertion-style":"error","capitalized-comments":"off","one-var":"off","sort-keys":"off","sort-imports":"off","func-style":["error","declaration",{"allowArrowFunctions":true}],"no-magic-numbers":["error",{"ignore":[0,1,2]}],"no-undefined":"off","no-ternary":"off"},"overrides":[{"files":["*.spec.mts","*.test.mts","*.spec.ts","*.test.ts"],"rules":{"@typescript-eslint/non-nullable-type-assertion-style":"off","@typescript-eslint/ban-types":"off","@typescript-eslint/require-await":"off","@typescript-eslint/consistent-type-definitions":"off","@typescript-eslint/ban-ts-comment":"off","@typescript-eslint/no-unnecessary-condition":"off","@typescript-eslint/consistent-indexed-object-style":"off","@typescript-eslint/no-unused-vars":"off","@typescript-eslint/no-unsafe-member-access":"off","line-comment-position":"off","no-inline-comments":"off","no-param-reassign":"off","id-length":"off","no-magic-numbers":"off","func-names":"off","no-duplicate-imports":"off","symbol-description":"off","no-invalid-this":"off"}}]},"jest":{"moduleFileExtensions":["js","mjs","cjs","ts","mts","json","node"],"extensionsToTreatAsEsm":[".mts"],"transform":{"^.+\\.mts$":["ts-jest",{"isolatedModules":true,"diagnostics":false,"useESM":true}],"^.+\\.ts$":["ts-jest",{"isolatedModules":true,"diagnostics":false,"useESM":false}]},"collectCoverageFrom":["<rootDir>/src/**","!<rootDir>/src/**/*.spec.mts","!<rootDir>/src/**/*.test.mts","!<rootDir>/src/**/*.spec.ts","!<rootDir>/src/**/*.test.ts"],"testMatch":["<rootDir>/src/**/*.spec.ts","<rootDir>/src/**/*.spec.mts"]},"files":["tsconfig.json","SECURITY.md","/src/"]}
1
+ {"name":"@checkdigit/typescript-config","version":"3.3.0-PR.30-a6df","description":"Check Digit standard Typescript configuration","prettier":"@checkdigit/prettier-config","engines":{"node":">=16"},"bin":{"builder":"./bin/builder.mjs"},"peerDependencies":{"@types/node":">=16","esbuild":"0.17.18","typescript":">=5.0.4 <5.1"},"repository":{"type":"git","url":"git+https://github.com/checkdigit/typescript-config.git"},"author":"Check Digit, LLC","license":"MIT","bugs":{"url":"https://github.com/checkdigit/typescript-config/issues"},"homepage":"https://github.com/checkdigit/typescript-config#readme","scripts":{"preversion":"npm test","postversion":"git push && git push --tags","prepare":"npm run build-builder","lint:fix":"eslint -f unix --ext .ts,.mts src --fix","lint":"eslint -f unix --ext .ts,.mts src","prettier":"prettier --ignore-path .gitignore --list-different .","prettier:fix":"prettier --ignore-path .gitignore --write .","test":"npm run ci:compile && npm run ci:test && npm run ci:lint && npm run ci:style","build-builder":"esbuild src/builder/index.mts --bundle --platform=node --format=esm --external:typescript --external:esbuild --outfile=build-builder/builder.mjs && mkdir -p bin && { echo '#!/usr/bin/env node'; cat build-builder/builder.mjs; } > bin/builder.mjs && chmod +x bin/builder.mjs","build-tsc-cjs":"rimraf build-tsc-cjs && tsc --outDir build-tsc-cjs","build-esbuild-cjs":"rimraf build-esbuild-cjs && esbuild ./src/*.ts ./src/*/*.ts --platform=node --bundle --format=cjs --sourcemap=inline --sources-content=false --outdir=build-esbuild-cjs","build-esbuild-cjs-bundle":"rimraf build-esbuild-cjs-bundle && esbuild src/test/index.test.ts --bundle --platform=node --format=cjs --sourcemap=inline --sources-content=false --outfile=build-esbuild-cjs-bundle/test/index.test.cjs","build-esbuild-esm":"rimraf build-esbuild-esm && node bin/builder.mjs --outDir=build-esbuild-esm","build-esbuild-esm-bundle":"rimraf build-esbuild-esm-bundle && esbuild src/test/index.test.ts --bundle --platform=node --format=esm --sourcemap=inline --sources-content=false --outfile=build-esbuild-esm-bundle/test/index.test.mjs","test-jest-esm":"NODE_OPTIONS=\"--experimental-vm-modules\" jest --coverage=false src/*.mts src/*/*.mts src/*/*/*.mts","test-jest-cjs":"jest --coverage=false src/*.ts src/*/*.ts src/*/*/*.ts","test-tsc-cjs":"node --test build-tsc-cjs/test/index.test.js","test-esbuild-cjs":"node --test build-esbuild-cjs/test/index.test.js","test-esbuild-cjs-bundle":"node --test build-esbuild-cjs-bundle/test/index.test.cjs","test-esbuild-esm":"node --test build-esbuild-esm/test/index.test.mjs","test-esbuild-esm-bundle":"echo 'node -test build-esbuild-esm-bundle/test/index.test.mjs'","ci:test":"npm run test-jest-cjs && npm run test-jest-esm &&npm run test-tsc-cjs && npm run test-esbuild-cjs && npm run test-esbuild-cjs-bundle && npm run test-esbuild-esm && npm run test-esbuild-esm-bundle","ci:compile":"npm run build-builder && npm run build-tsc-cjs && npm run build-esbuild-cjs && npm run build-esbuild-cjs-bundle && npm run build-esbuild-esm && npm run build-esbuild-esm-bundle","ci:lint":"npm run lint","ci:style":"npm run prettier"},"devDependencies":{"@checkdigit/prettier-config":"^3.4.0","@types/debug":"^4.1.7","@types/jest":"^29.5.1","@types/uuid":"^9.0.1","@typescript-eslint/eslint-plugin":"^5.59.5","@typescript-eslint/parser":"^5.59.5","debug":"^4.3.4","eslint":"^8.40.0","eslint-config-prettier":"^8.8.0","get-port":"^6.1.2","got":"^11.8.6","jest":"^29.5.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","uuid":"^9.0.0"},"eslintConfig":{"parser":"@typescript-eslint/parser","plugins":["@typescript-eslint"],"parserOptions":{"project":"./tsconfig.json"},"extends":["eslint:all","plugin:@typescript-eslint/recommended","plugin:@typescript-eslint/recommended-requiring-type-checking","plugin:@typescript-eslint/strict","prettier"],"rules":{"@typescript-eslint/non-nullable-type-assertion-style":"error","capitalized-comments":"off","one-var":"off","sort-keys":"off","sort-imports":"off","func-style":["error","declaration",{"allowArrowFunctions":true}],"no-magic-numbers":["error",{"ignore":[0,1,2]}],"no-undefined":"off","no-ternary":"off"},"overrides":[{"files":["*.spec.mts","*.test.mts","*.spec.ts","*.test.ts"],"rules":{"@typescript-eslint/non-nullable-type-assertion-style":"off","@typescript-eslint/ban-types":"off","@typescript-eslint/require-await":"off","@typescript-eslint/consistent-type-definitions":"off","@typescript-eslint/ban-ts-comment":"off","@typescript-eslint/no-unnecessary-condition":"off","@typescript-eslint/consistent-indexed-object-style":"off","@typescript-eslint/no-unused-vars":"off","@typescript-eslint/no-unsafe-member-access":"off","line-comment-position":"off","no-inline-comments":"off","no-param-reassign":"off","id-length":"off","no-magic-numbers":"off","func-names":"off","no-duplicate-imports":"off","symbol-description":"off","no-invalid-this":"off","max-lines-per-function":"off"}}]},"jest":{"moduleFileExtensions":["js","mjs","cjs","ts","mts","json","node"],"extensionsToTreatAsEsm":[".mts"],"transform":{"^.+\\.mts$":["ts-jest",{"isolatedModules":true,"diagnostics":false,"useESM":true}],"^.+\\.ts$":["ts-jest",{"isolatedModules":true,"diagnostics":false,"useESM":false}]},"collectCoverageFrom":["<rootDir>/src/**","!<rootDir>/src/**/*.spec.mts","!<rootDir>/src/**/*.test.mts","!<rootDir>/src/**/*.spec.ts","!<rootDir>/src/**/*.test.ts"],"testMatch":["<rootDir>/src/**/*.spec.ts","<rootDir>/src/**/*.spec.mts"]},"files":["tsconfig.json","SECURITY.md","/src/"]}
@@ -8,6 +8,7 @@ import typescript from 'typescript';
8
8
  import { PluginBuild, build } from 'esbuild';
9
9
 
10
10
  export interface BuilderOptions {
11
+ type: 'module' | 'commonjs';
11
12
  inDir: string;
12
13
  outDir: string;
13
14
  }
@@ -28,33 +29,35 @@ async function getFiles(directory: string): Promise<string[]> {
28
29
  return files.flat();
29
30
  }
30
31
 
31
- function setup(pluginBuild: PluginBuild) {
32
- pluginBuild.onResolve({ filter: /.*/u }, async (resolved) => {
33
- if (resolved.kind === 'entry-point' || !resolved.path.startsWith('.') || resolved.path.endsWith('.js')) {
34
- return { external: resolved.kind !== 'entry-point' };
35
- }
36
- let isDirectory = false;
37
- try {
38
- const stats = await fs.lstat(path.join(resolved.resolveDir, resolved.path));
39
- isDirectory = stats.isDirectory();
40
- } catch {
41
- // do nothing
42
- }
43
- let newPath = resolved.path;
44
- newPath += isDirectory ? `/index.mjs` : `.mjs`;
45
- return { path: newPath, external: true };
46
- });
32
+ function setup(type: 'module' | 'commonjs') {
33
+ const extension = type === 'module' ? 'mjs' : 'cjs';
34
+ return (pluginBuild: PluginBuild) => {
35
+ pluginBuild.onResolve({ filter: /.*/u }, async (resolved) => {
36
+ if (resolved.kind === 'entry-point' || !resolved.path.startsWith('.') || resolved.path.endsWith('.js')) {
37
+ return { external: resolved.kind !== 'entry-point' };
38
+ }
39
+ let isDirectory = false;
40
+ try {
41
+ const stats = await fs.lstat(path.join(resolved.resolveDir, resolved.path));
42
+ isDirectory = stats.isDirectory();
43
+ } catch {
44
+ // do nothing
45
+ }
46
+ let newPath = resolved.path;
47
+ newPath += isDirectory ? `/index.${extension}` : `.${extension}`;
48
+ return { path: newPath, external: true };
49
+ });
50
+ };
47
51
  }
48
52
 
49
53
  // eslint-disable-next-line func-names,max-lines-per-function,max-statements
50
- export default async function ({ inDir, outDir }: BuilderOptions): Promise<string[]> {
54
+ export default async function ({ type, inDir, outDir }: BuilderOptions): Promise<string[]> {
51
55
  const messages: string[] = [];
52
56
 
53
57
  /**
54
58
  * Emit declarations using typescript compiler
55
59
  */
56
- const sourceDirectory = inDir;
57
- const allSourceFiles = await getFiles(sourceDirectory);
60
+ const allSourceFiles = await getFiles(inDir);
58
61
  const productionSourceFiles = allSourceFiles.filter(
59
62
  // && !file.endsWith('.test.ts') && !file.endsWith('.spec.ts')
60
63
  (file) => file.endsWith('.ts')
@@ -71,7 +74,10 @@ export default async function ({ inDir, outDir }: BuilderOptions): Promise<strin
71
74
  outDir,
72
75
  });
73
76
  const emitResult = program.emit();
74
- const allDiagnostics = [...typescript.getPreEmitDiagnostics(program), ...emitResult.diagnostics];
77
+ const allDiagnostics = typescript.sortAndDeduplicateDiagnostics([
78
+ ...typescript.getPreEmitDiagnostics(program),
79
+ ...emitResult.diagnostics,
80
+ ]);
75
81
  for (const diagnostic of allDiagnostics) {
76
82
  if (diagnostic.file) {
77
83
  assert.ok(diagnostic.start !== undefined);
@@ -84,7 +90,7 @@ export default async function ({ inDir, outDir }: BuilderOptions): Promise<strin
84
90
  }
85
91
  }
86
92
  if (emitResult.emitSkipped) {
87
- throw new Error('TypeScript compilation failed');
93
+ throw new Error(`TypeScript compilation failed ${JSON.stringify(messages)}`);
88
94
  }
89
95
 
90
96
  /**
@@ -94,20 +100,23 @@ export default async function ({ inDir, outDir }: BuilderOptions): Promise<strin
94
100
  entryPoints: productionSourceFiles,
95
101
  bundle: true,
96
102
  platform: 'node',
97
- format: 'esm',
103
+ format: type === 'module' ? 'esm' : 'cjs',
98
104
  outdir: outDir,
99
105
  sourcemap: 'inline',
100
106
  sourcesContent: false,
101
- outExtension: { '.js': '.mjs' },
107
+ outExtension: { '.js': type === 'module' ? '.mjs' : '.cjs' },
102
108
  plugins: [
103
109
  {
104
110
  name: 'resolve-ts',
105
- setup,
111
+ setup: setup(type),
106
112
  },
107
113
  ],
108
114
  });
109
115
 
110
116
  messages.push(...buildResult.errors.map((error) => `esbuild error: ${error.text}`));
111
117
  messages.push(...buildResult.warnings.map((warning) => `esbuild warning: ${warning.text}`));
118
+ if (messages.length > 0) {
119
+ throw new Error(`esbuild failed ${JSON.stringify(messages)}`);
120
+ }
112
121
  return messages;
113
122
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { strict as assert } from 'node:assert';
4
4
  import { promises as fs } from 'node:fs';
5
+ import { createRequire } from 'node:module';
5
6
  import os from 'node:os';
6
7
  import path from 'node:path';
7
8
 
@@ -10,10 +11,17 @@ import { v4 as uuid } from 'uuid';
10
11
  // @ts-expect-error
11
12
  import builder from './builder.mts';
12
13
 
14
+ const require = createRequire(import.meta.url);
15
+
13
16
  const singleModule = {
14
17
  [`index.ts`]: `export const hello = 'world';`,
15
18
  };
16
19
 
20
+ const twoModules = {
21
+ [`index.ts`]: `import { hello } from './thing';\nexport default hello + 'world';\n`,
22
+ [`thing.ts`]: `export const hello = 'world';`,
23
+ };
24
+
17
25
  async function write(dir: string, files: Record<string, string>): Promise<void> {
18
26
  await fs.mkdir(dir, { recursive: true });
19
27
  await Promise.all(Object.entries(files).map(([name, content]) => fs.writeFile(path.join(dir, name), content)));
@@ -42,7 +50,13 @@ describe('test builder', () => {
42
50
  const inDir = path.join(os.tmpdir(), `in-dir-${id}`);
43
51
  const outDir = path.join(os.tmpdir(), `out-dir-${id}`);
44
52
  await write(inDir, { 'index.ts': 'bad code' });
45
- await assert.rejects(builder({ inDir, outDir }), { message: 'TypeScript compilation failed' });
53
+ await assert.rejects(builder({ type: 'module', inDir, outDir }), {
54
+ message: `TypeScript compilation failed ${JSON.stringify([
55
+ `tsc: ${inDir}/index.ts (1,1): Unexpected keyword or identifier.`,
56
+ `tsc: ${inDir}/index.ts (1,1): Cannot find name 'bad'.`,
57
+ `tsc: ${inDir}/index.ts (1,5): Cannot find name 'code'.`,
58
+ ])}`,
59
+ });
46
60
  await assert.rejects(read(outDir), {
47
61
  message: `ENOENT: no such file or directory, scandir '${outDir}'`,
48
62
  });
@@ -52,7 +66,7 @@ describe('test builder', () => {
52
66
  const id = uuid();
53
67
  const inDir = path.join(os.tmpdir(), `in-dir-${id}`);
54
68
  const outDir = path.join(os.tmpdir(), `out-dir-${id}`);
55
- await assert.rejects(builder({ inDir, outDir }), {
69
+ await assert.rejects(builder({ type: 'module', inDir, outDir }), {
56
70
  message: `ENOENT: no such file or directory, scandir '${inDir}'`,
57
71
  });
58
72
  await assert.rejects(read(outDir), {
@@ -65,7 +79,7 @@ describe('test builder', () => {
65
79
  const inDir = path.join(os.tmpdir(), `in-dir-${id}`);
66
80
  const outDir = path.join(os.tmpdir(), `out-dir-${id}`);
67
81
  await write(inDir, {});
68
- assert.deepEqual(await builder({ inDir, outDir }), []);
82
+ assert.deepEqual(await builder({ type: 'module', inDir, outDir }), []);
69
83
  await assert.rejects(read(outDir), {
70
84
  message: `ENOENT: no such file or directory, scandir '${outDir}'`,
71
85
  });
@@ -73,13 +87,152 @@ describe('test builder', () => {
73
87
 
74
88
  it('should build a single ESM module', async () => {
75
89
  const id = uuid();
76
- const inDir = path.join(os.tmpdir(), `in-dir-${id}`);
77
- const outDir = path.join(os.tmpdir(), `out-dir-${id}`);
90
+ const inDir = path.join(os.tmpdir(), `in-dir-${id}`, 'src');
91
+ const outDir = path.join(os.tmpdir(), `out-dir-${id}`, 'build');
78
92
  await write(inDir, singleModule);
79
- assert.deepEqual(await builder({ inDir, outDir }), []);
93
+ assert.deepEqual(await builder({ type: 'module', inDir, outDir }), []);
80
94
  assert.deepEqual(await read(outDir), {
81
95
  'index.d.ts': 'export declare const hello = "world";\n',
82
96
  'index.mjs': 'var hello = "world";\nexport {\n hello\n};\n',
83
97
  });
98
+
99
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
100
+ const output = await import(path.join(outDir, 'index.mjs'));
101
+ assert.equal(output.hello, 'world');
102
+ });
103
+
104
+ it('should build an ESM module that imports a second ESM module', async () => {
105
+ const id = uuid();
106
+ const inDir = path.join(os.tmpdir(), `in-dir-${id}`, 'src');
107
+ const outDir = path.join(os.tmpdir(), `out-dir-${id}`, 'build');
108
+ await write(inDir, twoModules);
109
+ assert.deepEqual(await builder({ type: 'module', inDir, outDir }), []);
110
+ assert.deepEqual(await read(outDir), {
111
+ 'index.d.ts': 'declare const _default: string;\nexport default _default;\n',
112
+ 'index.mjs':
113
+ 'import { hello } from "./thing.mjs";\n' +
114
+ 'var src_default = hello + "world";\n' +
115
+ 'export {\n' +
116
+ ' src_default as default\n' +
117
+ '};\n',
118
+ 'thing.d.ts': 'export declare const hello = "world";\n',
119
+ 'thing.mjs': 'var hello = "world";\nexport {\n hello\n};\n',
120
+ });
121
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
122
+ const output = await import(path.join(outDir, 'index.mjs'));
123
+ assert.equal(output.default, 'worldworld');
124
+ });
125
+
126
+ it('should build a single CJS module', async () => {
127
+ const id = uuid();
128
+ const inDir = path.join(os.tmpdir(), `in-dir-${id}`, 'src');
129
+ const outDir = path.join(os.tmpdir(), `out-dir-${id}`, 'build');
130
+ await write(inDir, singleModule);
131
+ assert.deepEqual(await builder({ type: 'commonjs', inDir, outDir }), []);
132
+ assert.deepEqual(await read(outDir), {
133
+ 'index.d.ts': 'export declare const hello = "world";\n',
134
+ 'index.cjs':
135
+ 'var __defProp = Object.defineProperty;\n' +
136
+ 'var __getOwnPropDesc = Object.getOwnPropertyDescriptor;\n' +
137
+ 'var __getOwnPropNames = Object.getOwnPropertyNames;\n' +
138
+ 'var __hasOwnProp = Object.prototype.hasOwnProperty;\n' +
139
+ 'var __export = (target, all) => {\n' +
140
+ ' for (var name in all)\n' +
141
+ ' __defProp(target, name, { get: all[name], enumerable: true });\n' +
142
+ '};\n' +
143
+ 'var __copyProps = (to, from, except, desc) => {\n' +
144
+ ' if (from && typeof from === "object" || typeof from === "function") {\n' +
145
+ ' for (let key of __getOwnPropNames(from))\n' +
146
+ ' if (!__hasOwnProp.call(to, key) && key !== except)\n' +
147
+ ' __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n' +
148
+ ' }\n' +
149
+ ' return to;\n' +
150
+ '};\n' +
151
+ 'var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);\n' +
152
+ '\n' +
153
+ 'var src_exports = {};\n' +
154
+ '__export(src_exports, {\n' +
155
+ ' hello: () => hello\n' +
156
+ '});\n' +
157
+ 'module.exports = __toCommonJS(src_exports);\n' +
158
+ 'var hello = "world";\n' +
159
+ '0 && (module.exports = {\n' +
160
+ ' hello\n' +
161
+ '});\n',
162
+ });
163
+ });
164
+
165
+ it('should build a CJS module that requires a second CJS module', async () => {
166
+ const id = uuid();
167
+ const inDir = path.join(os.tmpdir(), `in-dir-${id}`, 'src');
168
+ const outDir = path.join(os.tmpdir(), `out-dir-${id}`, 'build');
169
+ await write(inDir, twoModules);
170
+ assert.deepEqual(await builder({ type: 'commonjs', inDir, outDir }), []);
171
+ assert.deepEqual(await read(outDir), {
172
+ 'index.cjs':
173
+ 'var __defProp = Object.defineProperty;\n' +
174
+ 'var __getOwnPropDesc = Object.getOwnPropertyDescriptor;\n' +
175
+ 'var __getOwnPropNames = Object.getOwnPropertyNames;\n' +
176
+ 'var __hasOwnProp = Object.prototype.hasOwnProperty;\n' +
177
+ 'var __export = (target, all) => {\n' +
178
+ ' for (var name in all)\n' +
179
+ ' __defProp(target, name, { get: all[name], enumerable: true });\n' +
180
+ '};\n' +
181
+ 'var __copyProps = (to, from, except, desc) => {\n' +
182
+ ' if (from && typeof from === "object" || typeof from === "function") {\n' +
183
+ ' for (let key of __getOwnPropNames(from))\n' +
184
+ ' if (!__hasOwnProp.call(to, key) && key !== except)\n' +
185
+ ' __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n' +
186
+ ' }\n' +
187
+ ' return to;\n' +
188
+ '};\n' +
189
+ 'var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);\n' +
190
+ '\n' +
191
+ 'var src_exports = {};\n' +
192
+ '__export(src_exports, {\n' +
193
+ ' default: () => src_default\n' +
194
+ '});\n' +
195
+ 'module.exports = __toCommonJS(src_exports);\n' +
196
+ 'var import_thing = require("./thing.cjs");\n' +
197
+ 'var src_default = import_thing.hello + "world";\n',
198
+ 'index.d.ts': 'declare const _default: string;\nexport default _default;\n',
199
+ 'thing.cjs':
200
+ 'var __defProp = Object.defineProperty;\n' +
201
+ 'var __getOwnPropDesc = Object.getOwnPropertyDescriptor;\n' +
202
+ 'var __getOwnPropNames = Object.getOwnPropertyNames;\n' +
203
+ 'var __hasOwnProp = Object.prototype.hasOwnProperty;\n' +
204
+ 'var __export = (target, all) => {\n' +
205
+ ' for (var name in all)\n' +
206
+ ' __defProp(target, name, { get: all[name], enumerable: true });\n' +
207
+ '};\n' +
208
+ 'var __copyProps = (to, from, except, desc) => {\n' +
209
+ ' if (from && typeof from === "object" || typeof from === "function") {\n' +
210
+ ' for (let key of __getOwnPropNames(from))\n' +
211
+ ' if (!__hasOwnProp.call(to, key) && key !== except)\n' +
212
+ ' __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n' +
213
+ ' }\n' +
214
+ ' return to;\n' +
215
+ '};\n' +
216
+ 'var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);\n' +
217
+ '\n' +
218
+ 'var thing_exports = {};\n' +
219
+ '__export(thing_exports, {\n' +
220
+ ' hello: () => hello\n' +
221
+ '});\n' +
222
+ 'module.exports = __toCommonJS(thing_exports);\n' +
223
+ 'var hello = "world";\n' +
224
+ '0 && (module.exports = {\n' +
225
+ ' hello\n' +
226
+ '});\n',
227
+ 'thing.d.ts': 'export declare const hello = "world";\n',
228
+ });
229
+
230
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
231
+ const output1 = require(path.join(outDir, 'index.cjs'));
232
+ assert.equal(output1.default, 'worldworld');
233
+
234
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
235
+ const output2 = await import(path.join(outDir, 'index.cjs'));
236
+ assert.equal(output2.default.default, 'worldworld');
84
237
  });
85
238
  });
@@ -9,18 +9,24 @@ import { parseArgs } from 'node:util';
9
9
  import builder from './builder.mts';
10
10
 
11
11
  const {
12
- values: { inDir, outDir },
12
+ values: { type, inDir, outDir },
13
13
  } = parseArgs({
14
14
  options: {
15
+ type: { type: 'string', short: 't', default: 'module' },
15
16
  inDir: { type: 'string', short: 'i', default: 'src' },
16
17
  outDir: { type: 'string', short: 'o', default: 'build' },
17
18
  },
18
19
  });
19
20
 
21
+ assert.ok(type === 'module' || type === 'commonjs', 'type must be module or commonjs');
20
22
  assert.ok(inDir !== undefined, 'inDir is required');
21
23
  assert.ok(outDir !== undefined, 'outDir is required');
22
24
 
23
- const messages = await builder({ inDir: path.join(process.cwd(), inDir), outDir: path.join(process.cwd(), outDir) });
25
+ const messages = await builder({
26
+ type,
27
+ inDir: path.join(process.cwd(), inDir),
28
+ outDir: path.join(process.cwd(), outDir),
29
+ });
24
30
  if (messages.length > 0) {
25
31
  // eslint-disable-next-line no-console
26
32
  console.warn(JSON.stringify(messages, undefined, 2));