susee 2.2.4 → 2.3.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/README.md CHANGED
@@ -10,7 +10,8 @@
10
10
  [![NPM][nodei_img]][nodei_url]
11
11
 
12
12
  [![npm version][npm_v_img]][npm_v_url] [![license][license_img]](LICENSE) [![OpenSSF Baseline](https://www.bestpractices.dev/projects/13115/baseline)](https://www.bestpractices.dev/projects/13115) [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13115/badge)](https://www.bestpractices.dev/projects/13115)
13
-
13
+ > [!IMPORTANT]
14
+ > Use **susee v2.3.0 or above**. The core bundler was ported to Rust in v2.3.0, fixing multiple bugs present in earlier versions. Older versions are no longer recommended.
14
15
  ## Overview
15
16
 
16
17
  `susee` is a **TypeScript-first bundler** powered by `oxc`, specialized for library packages. Unlike general-purpose bundlers, `susee` focuses on consolidating a package's local TypeScript dependency tree into consolidated source units and compiling them into dual-format artifacts (ESM and CommonJS).
@@ -91,6 +92,8 @@ Susee reads your config, bundles each entry point, compiles to ESM and/or Common
91
92
  ```
92
93
  susee build Build using susee.config.{ts,js,mjs}
93
94
  susee init Generate susee.config.{ts,js,mjs}
95
+ susee check Run lint checks on a dependency tree without bundling
96
+ susee bundle <entry> [options] Bundle a single entry file to disk without compiling
94
97
  susee --version / -v Print version
95
98
  susee --help / -h Show help
96
99
  susee build <entry> [options] Build from a single entry file
@@ -102,12 +105,16 @@ susee build <entry> [options] Build from a single entry file
102
105
  |------|------|---------|-------------|
103
106
  | `--entry <path>` | string | — | Entry file (optional if given positionally) |
104
107
  | `--outdir <path>` | string | `dist` | Output directory |
105
- | `--format` | `cjs\|commonjs\|esm` | `esm` | Output module format |
108
+ | `--format` | `cjs\|commonjs\|esm\|both` | `esm` | Output module format (`both` = CJS + ESM) |
106
109
  | `--tsconfig <path>` | string | `undefined` | Custom tsconfig path |
107
110
  | `--allow-update[=true\|false]` | boolean | `false` | Allow `package.json` updates |
108
111
  | `--minify[=true\|false]` | boolean | `false` | Minify output JS |
109
112
  | `--check[=true\|false]` | boolean | `false` | Run bundler lint checks |
110
113
 
114
+ ### Bundle Flags
115
+
116
+ The `susee bundle` command writes the bundled source (before TypeScript compilation) to disk. It supports `--entry`, `--outdir`, and `--check[=true|false]`.
117
+
111
118
  Flags accept both `--flag=value` and `--flag value` syntax.
112
119
 
113
120
  ### Examples
@@ -115,12 +122,18 @@ Flags accept both `--flag=value` and `--flag value` syntax.
115
122
  ```sh
116
123
  npx susee build src/index.ts --outdir dist
117
124
  npx susee build src/index.ts --format commonjs
125
+ npx susee build src/index.ts --format both # emit CJS + ESM
118
126
  npx susee build --entry src/index.ts --format esm --tsconfig tsconfig.build.json
119
127
  npx susee build src/index.ts --minify
128
+ npx susee build src/index.ts --check # run lint checks during build
129
+ npx susee bundle src/index.ts --outdir bundled # write bundled source only
130
+ npx susee check # lint the dependency tree from config
120
131
  ```
121
132
 
122
133
  ## Programmatic API
123
134
 
135
+ ### `build()`
136
+
124
137
  ```ts
125
138
  import { build, type SuSeeConfig } from "susee";
126
139
 
@@ -137,6 +150,26 @@ await build(config);
137
150
 
138
151
  `build()` resolves options from the argument first, then from a root config file. If neither is available it logs an error and exits with code 1.
139
152
 
153
+ ### `suseeBundle()`
154
+
155
+ Bundle a single entry point into a consolidated source string without compiling or writing to disk:
156
+
157
+ ```ts
158
+ import { suseeBundle, type CheckOptions } from "susee";
159
+
160
+ const code: string = suseeBundle("src/index.ts");
161
+
162
+ // with lint checks enabled
163
+ const checks: CheckOptions = {
164
+ checkAnonymous: true,
165
+ checkDefaultExports: true,
166
+ checkNpmInstalled: true,
167
+ };
168
+ const checked = suseeBundle("src/index.ts", checks);
169
+ ```
170
+
171
+ `suseeBundle()` runs the oxc-powered bundler over the entry's local dependency tree and returns the bundled source. When `CheckOptions` are provided the bundler runs diagnostics (anonymous declarations, default exports, npm-installed deps) before returning.
172
+
140
173
  ## How It Works
141
174
 
142
175
  ```mermaid
@@ -172,13 +205,14 @@ The pipeline bundles each entry point's local dependency tree into a single sour
172
205
 
173
206
  ```
174
207
  src/
175
- ├── index.ts # Public API — re-exports build + SuSeeConfig
208
+ ├── index.ts # Public API — re-exports build, suseeBundle, SuSeeConfig, CheckOptions
176
209
  ├── build.ts # Build orchestrator — resolves config, runs Compiler
177
- ├── bundler.ts # Wrapper around @suseejs/susee_bundler (oxc)
210
+ ├── bundler.ts # Wrapper around @suseejs/susee_bundler (oxc) + CLI bundle writer
178
211
  ├── cli/
179
- │ ├── index.ts # CLI entrypoint & command dispatch
180
- │ ├── parse_args.ts # Parses CLI flags into SuSeeConfig
212
+ │ ├── index.ts # CLI entrypoint & command dispatch (build/init/check/bundle)
213
+ │ ├── parse_args.ts # Parses CLI flags into SuSeeConfig / bundle opts
181
214
  │ ├── init.ts # `susee init` — scaffolds config file
215
+ │ ├── lint.ts # `susee check` — runs suseeLint over the dependency tree
182
216
  │ └── print_help.ts # `susee --help` output
183
217
  ├── compiler/
184
218
  │ ├── index.ts # Compiler class — bundles + emits CJS/ESM + types
@@ -256,8 +290,8 @@ npm run fmt # oxfmt
256
290
 
257
291
  <!-- Need to update version -->
258
292
 
259
- [sb_img]: https://badge.socket.dev/npm/package/susee/1.5.2
260
- [sb_url]: https://badge.socket.dev/npm/package/susee/1.5.2
293
+ [sb_img]: https://badge.socket.dev/npm/package/susee/2.2.4
294
+ [sb_url]: https://badge.socket.dev/npm/package/susee/2.2.4
261
295
 
262
296
  <!-- -->
263
297
 
@@ -2,9 +2,8 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import process from 'node:process';
4
4
  import readline from 'node:readline/promises';
5
- import tcolor from '@suseejs/color';
6
5
  import ts6 from '@suseejs/ts6';
7
- import { LogTimer, logError, logInfo, suseeBundler } from '@suseejs/susee_bundler';
6
+ import { LogTimer, logError, logInfo, logWarning, suseeBundler, suseeLint } from '@suseejs/susee_bundler';
8
7
  import { minify } from 'oxc-minify';
9
8
  //src/cli/init.ts
10
9
  const tsFileText = `
@@ -181,7 +180,7 @@ function checkEntries(entries) {
181
180
  for (const obj of entries) {
182
181
  if (!fs.existsSync(path.resolve(process.cwd(), obj.entry))) {
183
182
  const info = 'Entry file error';
184
- const cause = `Entry file ${obj.entry} dose not exists.`;
183
+ const cause = `Entry file ${obj.entry} does not exist.`;
185
184
  logError(info, cause, true);
186
185
  }
187
186
  }
@@ -238,6 +237,52 @@ async function finalSuseeConfig() {
238
237
  return generateBuildOptions(config);
239
238
  }
240
239
  }
240
+ async function generateFinalBuildOptions(options) {
241
+ let buildOptions = {};
242
+ const _buildOptions = await finalSuseeConfig();
243
+ if (!options && !_buildOptions) {
244
+ const info = 'Required build options or susee config file at root.You can use `npx susee init` to create susee config file at root';
245
+ const cause = 'No build options or susee config file at root.';
246
+ logError(info, cause, true);
247
+ }
248
+ if (options) {
249
+ buildOptions = generateBuildOptions(options);
250
+ }
251
+ else if (_buildOptions) {
252
+ buildOptions = _buildOptions;
253
+ }
254
+ return buildOptions;
255
+ }
256
+ function bundler(point) {
257
+ const root = process.cwd();
258
+ const bundled = suseeBundler(point.entry, root, point.checks);
259
+ if (bundled.moduleType === 2) {
260
+ logWarning('Your project contains CJS files that were auto-converted. Consider migrating to ESM for better tree-shaking.');
261
+ }
262
+ return bundled.bundledCode;
263
+ }
264
+ function suseeBundle(entry, checkOptions) {
265
+ const root = process.cwd();
266
+ const opts = checkOptions ? checkOptions : {
267
+ checkAnonymous: false,
268
+ checkDefaultExports: false,
269
+ checkNpmInstalled: false
270
+ };
271
+ const bundled = suseeBundler(entry, root, opts);
272
+ if (bundled.moduleType === 2) {
273
+ logWarning('Your project contains CJS files that were auto-converted. Consider migrating to ESM for better tree-shaking.');
274
+ }
275
+ return bundled.bundledCode;
276
+ }
277
+ async function suseeCliBundle(opts) {
278
+ const fileName = path.basename(opts.entry);
279
+ const outDir = opts.outDir ? path.resolve(process.cwd(), opts.outDir) : process.cwd();
280
+ const outFilePath = path.join(outDir, fileName);
281
+ const code = suseeBundle(opts.entry, opts.check);
282
+ if (!fs.existsSync(outDir))
283
+ await fs.promises.mkdir(outDir, { recursive: true });
284
+ await fs.promises.writeFile(outFilePath, code);
285
+ }
241
286
  function fail(message) {
242
287
  const info = message;
243
288
  const cause = '';
@@ -266,24 +311,38 @@ function parseBooleanFlag(flag, value) {
266
311
  return false;
267
312
  fail(`Type of ${flag} must be boolean.`);
268
313
  }
314
+ function parseBundleBool(value) {
315
+ if (value === 'true')
316
+ return true;
317
+ if (value === 'false')
318
+ return false;
319
+ fail(`${value} must be "true" or "false".`);
320
+ }
269
321
  function parseArgs(argv) {
270
- const opts = {};
322
+ const buildOpts = {};
323
+ const bundleOpts = {};
271
324
  for (let index = 0; index < argv.length; index += 1) {
272
325
  const argument = argv[index];
273
- if (index === 0 && !argument.startsWith('--') && isFile(argument)) {
274
- opts.entry = argument;
326
+ if (!argument.startsWith('--') && isFile(argument)) {
327
+ if (buildOpts.entry && isFile(buildOpts.entry))
328
+ fail('Entry point already exists.');
329
+ buildOpts.entry = argument;
330
+ bundleOpts.entry = argument;
275
331
  continue;
276
332
  }
277
- const [flag, inlineValue] = argument.split('=', 2);
333
+ const eqIndex = argument.indexOf('=');
334
+ const flag = eqIndex === -1 ? argument : argument.slice(0, eqIndex);
335
+ const inlineValue = eqIndex === -1 ? undefined : argument.slice(eqIndex + 1);
278
336
  const nextValue = argv[index + 1];
279
337
  const value = inlineValue ?? nextValue;
280
338
  switch (flag) {
281
339
  case '--entry':
282
340
  if (!value || value.startsWith('--'))
283
341
  fail('Entry point required.');
284
- if (opts.entry && isFile(opts.entry))
342
+ if (buildOpts.entry && isFile(buildOpts.entry))
285
343
  fail('Entry point already exists.');
286
- opts.entry = value;
344
+ buildOpts.entry = value;
345
+ bundleOpts.entry = value;
287
346
  if (inlineValue === undefined) {
288
347
  index += 1;
289
348
  }
@@ -291,16 +350,17 @@ function parseArgs(argv) {
291
350
  case '--outdir':
292
351
  if (!value || value.startsWith('--'))
293
352
  fail('Output directory required.');
294
- opts.outDir = value;
353
+ buildOpts.outDir = value;
354
+ bundleOpts.outDir = value;
295
355
  if (inlineValue === undefined) {
296
356
  index += 1;
297
357
  }
298
358
  break;
299
359
  case '--format':
300
- if (value !== 'cjs' && value !== 'commonjs' && value !== 'esm') {
360
+ if (value !== 'cjs' && value !== 'commonjs' && value !== 'esm' && value !== 'both') {
301
361
  fail('Format must be cjs, commonjs, esm, both.');
302
362
  }
303
- opts.format = value === 'cjs' || value === 'commonjs' ? ['commonjs'] : value === 'esm' ? ['esm'] : value === 'both' ? ['commonjs', 'esm'] : undefined;
363
+ buildOpts.format = value === 'cjs' || value === 'commonjs' ? ['commonjs'] : value === 'esm' ? ['esm'] : value === 'both' ? ['commonjs', 'esm'] : undefined;
304
364
  if (inlineValue === undefined) {
305
365
  index += 1;
306
366
  }
@@ -308,82 +368,106 @@ function parseArgs(argv) {
308
368
  case '--tsconfig':
309
369
  if (!value || value.startsWith('--'))
310
370
  fail('Tsconfig path required.');
311
- opts.tsconfig = value;
371
+ buildOpts.tsconfig = value;
312
372
  if (inlineValue === undefined) {
313
373
  index += 1;
314
374
  }
315
375
  break;
316
376
  case '--allow-update':
317
377
  if (inlineValue !== undefined) {
318
- opts.allowUpdate = parseBooleanFlag('allow update', inlineValue);
378
+ buildOpts.allowUpdate = parseBooleanFlag('allow update', inlineValue);
319
379
  }
320
380
  else if (nextValue === 'true' || nextValue === 'false') {
321
- opts.allowUpdate = parseBooleanFlag('allow update', nextValue);
381
+ buildOpts.allowUpdate = parseBooleanFlag('allow update', nextValue);
322
382
  index += 1;
323
383
  }
324
384
  else {
325
- opts.allowUpdate = true;
385
+ buildOpts.allowUpdate = true;
326
386
  }
327
387
  break;
328
388
  case '--check':
329
389
  if (inlineValue !== undefined) {
330
- opts.check = parseBooleanFlag('check', inlineValue);
390
+ buildOpts.check = parseBooleanFlag('check', inlineValue);
391
+ bundleOpts.check = parseBundleBool(inlineValue);
331
392
  }
332
393
  else if (nextValue === 'true' || nextValue === 'false') {
333
- opts.check = parseBooleanFlag('check', nextValue);
394
+ buildOpts.check = parseBooleanFlag('check', nextValue);
395
+ bundleOpts.check = parseBundleBool(nextValue);
334
396
  index += 1;
335
397
  }
336
398
  else {
337
- opts.check = true;
399
+ buildOpts.check = true;
400
+ bundleOpts.check = true;
338
401
  }
339
402
  break;
340
403
  case '--minify':
341
404
  if (inlineValue !== undefined) {
342
- opts.minify = parseBooleanFlag('minify', inlineValue);
405
+ buildOpts.minify = parseBooleanFlag('minify', inlineValue);
343
406
  }
344
407
  else if (nextValue === 'true' || nextValue === 'false') {
345
- opts.minify = parseBooleanFlag('minify', nextValue);
408
+ buildOpts.minify = parseBooleanFlag('minify', nextValue);
346
409
  index += 1;
347
410
  }
348
411
  else {
349
- opts.minify = true;
412
+ buildOpts.minify = true;
350
413
  }
351
414
  break;
352
415
  }
353
416
  }
354
- return opts;
417
+ return {
418
+ buildOpts,
419
+ bundleOpts
420
+ };
355
421
  }
356
422
  function cliConfig(argv) {
357
- const cliOpts = parseArgs(argv);
358
- if (isEmptyObject(cliOpts))
423
+ const opts = parseArgs(argv).buildOpts;
424
+ if (isEmptyObject(opts))
359
425
  return undefined;
360
426
  const point = {
361
- entry: cliOpts.entry ?? '',
427
+ entry: opts.entry ?? '',
362
428
  exportPath: '.',
363
- format: cliOpts.format ?? ['esm'],
364
- tsconfigFilePath: cliOpts.tsconfig ?? undefined,
365
- minify: cliOpts.minify ?? false,
429
+ format: opts.format ?? ['esm'],
430
+ tsconfigFilePath: opts.tsconfig ?? undefined,
431
+ minify: opts.minify ?? false,
366
432
  checks: {
367
- checkAnonymous: cliOpts.check ? true : false,
368
- checkDefaultExports: cliOpts.check ? true : false,
369
- checkNpmInstalled: cliOpts.check ? true : false
433
+ checkAnonymous: opts.check ? true : false,
434
+ checkDefaultExports: opts.check ? true : false,
435
+ checkNpmInstalled: opts.check ? true : false
370
436
  }
371
437
  };
372
438
  if (point.entry === '')
373
439
  return undefined;
374
440
  const config = {
375
441
  entryPoints: [point],
376
- outDir: cliOpts.outDir ?? 'dist',
377
- allowUpdatePackageJson: cliOpts.allowUpdate ?? false
442
+ outDir: opts.outDir ?? 'dist',
443
+ allowUpdatePackageJson: opts.allowUpdate ?? false
378
444
  };
379
445
  return config;
380
446
  }
447
+ function cliBundleOpts(argv) {
448
+ const opts = parseArgs(argv).bundleOpts;
449
+ if (isEmptyObject(opts))
450
+ return undefined;
451
+ if (!opts.entry)
452
+ return undefined;
453
+ const options = {
454
+ entry: opts.entry,
455
+ outDir: opts.outDir,
456
+ check: opts.check ? {
457
+ checkAnonymous: true,
458
+ checkDefaultExports: true,
459
+ checkNpmInstalled: true
460
+ } : undefined
461
+ };
462
+ return options;
463
+ }
381
464
  //src/cli/print_help.ts
382
465
  function printHelp() {
383
466
  console.log(`Susee CLI.
384
467
  Usage:
385
468
  susee build Build using susee.config.{ts,js,mjs}
386
469
  susee init Generate susee.config.{ts,js,mjs}
470
+ susee check Run lint checks on a dependency tree without bundling.
387
471
  susee --help Show this message
388
472
  susee build <entry> [options] Build from a single entry file
389
473
  Options:
@@ -393,7 +477,7 @@ Options:
393
477
  --tsconfig <path> Custom tsconfig path. (default to undefined)
394
478
  --allow-update[=true|false] Enable package.json update. (default to false)
395
479
  --minify[=true|false] Enable minify to output JS code.(default to false)
396
- --check[=true|false] Enable minify to output JS code.(default to false)
480
+ --check[=true|false] Enable lint checks on bundled output.(default to false)
397
481
  Notes:
398
482
  Duplicate top-level declarations fail the build with file and location output.
399
483
  Rename conflicting declarations in source files before bundling.
@@ -432,8 +516,9 @@ var files;
432
516
  files_1.deleteFile = deleteFile;
433
517
  async function readFile(filePath) {
434
518
  if (!existsPath(filePath)) {
435
- console.error(tcolor.magenta(`> ${filePath} does not exists `));
436
- process.exit(1);
519
+ const info = `${filePath} does not exists`;
520
+ const cause = `When reading ${filePath}, file does not exists`;
521
+ logError(info, cause, true);
437
522
  }
438
523
  filePath = resolvePath(filePath);
439
524
  const readContent = await fs.promises.readFile(filePath);
@@ -510,7 +595,9 @@ var files;
510
595
  const pkgFile = resolvePath('package.json');
511
596
  const pkgtext = await readJsonFile(pkgFile);
512
597
  let { name, version, description, main, module, type, types, exports, ...rest } = pkgtext;
513
- type = 'module';
598
+ const hasCjs = files.commonjs !== undefined;
599
+ const hasEsm = files.esm !== undefined;
600
+ type = hasCjs && !hasEsm ? 'commonjs' : 'module';
514
601
  let _main = {};
515
602
  let _module = {};
516
603
  let _types = {};
@@ -519,7 +606,11 @@ var files;
519
606
  _main = files.main ? { main: path.relative(process.cwd(), files.main) } : {};
520
607
  _module = files.module ? { module: path.relative(process.cwd(), files.module) } : {};
521
608
  _types = files.types ? { types: path.relative(process.cwd(), files.types) } : {};
522
- _exports = { exports: { ...getExports(files, exportPath) } };
609
+ const normalizedExports = exports && typeof exports === 'object' && !Array.isArray(exports) ? { ...exports } : {};
610
+ _exports = { exports: {
611
+ ...normalizedExports,
612
+ ...getExports(files, exportPath)
613
+ } };
523
614
  }
524
615
  else {
525
616
  _main = main ? { main } : {};
@@ -572,7 +663,7 @@ function jsxCompilerOptions(sourceCode, compilerOptions, isJsx) {
572
663
  const pattern = `import\\s+(?:.*?)\\s+from\\s+("${txt}"|"${txt}\\/.*")`;
573
664
  const re = new RegExp(pattern, 'gm');
574
665
  if (!re.test(sourceCode)) {
575
- console.error('[jsx-runtime-mismatch-error]:\nJSX syntax found in bundled code,but its not react runtime and jsx-runtime from bundled code and jsxImportSource from tsconfig are mismatched.`');
666
+ console.error('[jsx-runtime-mismatch-error]:\nJSX syntax found in bundled code,but its not react runtime and jsx-runtime from bundled code and jsxImportSource from tsconfig are mismatched.');
576
667
  process.exit(1);
577
668
  }
578
669
  }
@@ -739,18 +830,6 @@ function getCompilerOptions(customConfigPath) {
739
830
  defaultOptions
740
831
  };
741
832
  }
742
- //src/bundler.ts
743
- function bundler(point) {
744
- // const bundledCodeCache: WeakMap<BuildEntryPoint, string> = new WeakMap();
745
- const root = process.cwd();
746
- // let bundledCode = bundledCodeCache.get(point);
747
- // if (!bundledCode) {
748
- // bundledCode = suseeBundler(point.entry,root,point.checks).bundledCode;
749
- // bundledCodeCache.set(point, bundledCode);
750
- // }
751
- // return bundledCode;
752
- return suseeBundler(point.entry, root, point.checks).bundledCode;
753
- }
754
833
  //src/helpers/minify.ts
755
834
  async function oxcMinify(fileName, code, point) {
756
835
  const options = typeof point.minify === 'object' && typeof point.minify !== 'boolean' ? point.minify.options : undefined;
@@ -758,7 +837,6 @@ async function oxcMinify(fileName, code, point) {
758
837
  return result.code;
759
838
  }
760
839
  //src/compiler/index.ts
761
- //import { utils } from "../helpers/utilities.js";
762
840
  /**
763
841
  * Checks if the given code string contains JSX syntax.
764
842
  * @param code The content of the file as a string.
@@ -872,6 +950,8 @@ class Compiler {
872
950
  }
873
951
  if (isMain && this._files.esm) {
874
952
  this._files.module = this._files.esm;
953
+ if (this._files.esmTypes)
954
+ this._files.types = this._files.esmTypes;
875
955
  }
876
956
  }
877
957
  await files.writeFile(mainFilePath, compiledCode);
@@ -888,6 +968,15 @@ class Compiler {
888
968
  async compile() {
889
969
  await files.clearFolder(this._object.outDir);
890
970
  for (const point of this._object.buildEntryPoints) {
971
+ this._files = {
972
+ commonjs: undefined,
973
+ commonjsTypes: undefined,
974
+ esm: undefined,
975
+ esmTypes: undefined,
976
+ main: undefined,
977
+ module: undefined,
978
+ types: undefined
979
+ };
891
980
  const bundleCode = bundler(point);
892
981
  for (const format of point.format) {
893
982
  switch (format) {
@@ -920,23 +1009,36 @@ class Compiler {
920
1009
  */
921
1010
  async function build(options) {
922
1011
  const buildTime = new LogTimer();
923
- let buildOptions = {};
924
- const _buildOptions = await finalSuseeConfig();
925
- if (!options && !_buildOptions) {
926
- const info = 'Required build options or susee config file at root.You can use `npx susee init` to create susee config file at root';
927
- const cause = 'No build options or susee config file at root.';
928
- logError(info, cause, true);
929
- }
930
- if (options) {
931
- buildOptions = generateBuildOptions(options);
932
- }
933
- else if (_buildOptions) {
934
- buildOptions = _buildOptions;
935
- }
1012
+ const buildOptions = await generateFinalBuildOptions(options);
936
1013
  const compiler = new Compiler(buildOptions);
937
1014
  await compiler.compile();
938
1015
  buildTime.buildTime();
939
1016
  }
1017
+ //src/cli/lint.ts
1018
+ async function suseeCheck() {
1019
+ const buildOptions = await generateFinalBuildOptions();
1020
+ const lintOptions = {
1021
+ checkAnonymous: true,
1022
+ checkDefaultExports: true,
1023
+ checkNpmInstalled: true
1024
+ };
1025
+ for (const point of buildOptions.buildEntryPoints) {
1026
+ const result = suseeLint(point.entry, '.', lintOptions);
1027
+ for (const diag of result.errors) {
1028
+ const location = `${diag.file}:${diag.line}:${diag.column}`;
1029
+ const details = diag.details.length ? `\n${diag.details.map((d) => ` ${d}`).join('\n')}` : '';
1030
+ logError(`[${diag.rule}] ${location} — ${diag.message}${details}`, diag.rule);
1031
+ }
1032
+ for (const diag of result.warnings) {
1033
+ const location = `${diag.file}:${diag.line}:${diag.column}`;
1034
+ const details = diag.details.length ? `\n${diag.details.map((d) => ` ${d}`).join('\n')}` : '';
1035
+ logWarning(`[${diag.rule}] ${location} — ${diag.message}${details}`);
1036
+ }
1037
+ if (result.errors.length === 0 && result.warnings.length === 0) {
1038
+ logInfo(`All checks passed for ${point.entry}`);
1039
+ }
1040
+ }
1041
+ }
940
1042
  //src/cli/index.ts
941
1043
  async function getPackageVersion() {
942
1044
  const pkgPath = path.resolve(process.cwd(), 'package.json');
@@ -965,6 +1067,9 @@ async function cliBuild() {
965
1067
  case 'init':
966
1068
  await cliInit();
967
1069
  break;
1070
+ case 'check':
1071
+ await suseeCheck();
1072
+ break;
968
1073
  case '--version':
969
1074
  case '-v':
970
1075
  logInfo(`susee v${version}`);
@@ -983,6 +1088,16 @@ async function cliBuild() {
983
1088
  const config = cliConfig(restArgs);
984
1089
  await build(config);
985
1090
  }
1091
+ else if (args.length > 1 && args[0] === 'bundle') {
1092
+ const restArgs = args.slice(1);
1093
+ const opts = cliBundleOpts(restArgs);
1094
+ if (opts) {
1095
+ await suseeCliBundle(opts);
1096
+ }
1097
+ else {
1098
+ errorLog();
1099
+ }
1100
+ }
986
1101
  else {
987
1102
  errorLog();
988
1103
  }