as-test 1.1.8 → 1.1.10

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/CHANGELOG.md CHANGED
@@ -1,8 +1,21 @@
1
1
  # Change Log
2
2
 
3
+ ## 2026-05-19 - v1.1.10
4
+
5
+ - feat: when the user already declares `--transform json-as/...` in `buildOptions.args` or in their referenced `asconfig.json` (top-level `options.transform`, any `targets.*.transform`, or via a single level of `extends`), as-test no longer adds its own auto-include — letting users bring their own json-as version or load path. Detection matches bare specifiers (`json-as`, `json-as/transform`), absolute paths, and `./node_modules/...` paths.
6
+
7
+ ## 2026-05-19 - v1.1.9
8
+
9
+ - fix: spec files that share a basename across subdirectories (e.g. `sqli/flags.spec.ts` and `sqli_v2/flags.spec.ts`) now build to their disambiguated artifact names across `ast test`, `ast run`, and `ast fuzz` — even when only one of them is being built. Previously the single-file build paths, the selector-filtered top-level build, the per-mode test/run dispatch, the plan listing, and the fuzz runner all computed duplicates from a local (and often single-element) file list, never matched anything, and clobbered each other into a single `flags.spec.wasm` / `parser.fuzz.wasm`; the runner then reported `bindings artifact not found`. Every call site now computes the duplicate set against the full configured input glob (`config.input` for tests/runs, `config.fuzz.input` when `overrides.kind === "fuzz"`), matching the runner's lookup behavior.
10
+ - chore: as-test's own suite now includes nested fixtures (`assembly/__tests__/nested/array.spec.ts`, `assembly/__fuzz__/nested/array.fuzz.ts`) that share basenames with siblings at the top level, exercising the disambiguation path end-to-end against the real build/run pipeline. The repo `as-test.config.json` inputs were widened to `**/*.spec.ts` / `**/*.fuzz.ts` to pick them up.
11
+ - chore: `npm test` now runs both the AssemblyScript spec suite (`npm run test:as`) and the Node integration suite (`npm run test:integration`) in one command. `release:check` and `prepublishOnly` no longer need to invoke `test:integration` separately.
12
+ - chore: GitHub workflows (`as-test.yml`, `release.yml`) now run `test:integration` after `test:ci`, so the Node integration suite gates PRs and releases (previously CI only ran the AS spec suite).
13
+
3
14
  ## 2026-05-18 - v1.1.8
4
15
 
5
- - chore: `ast init` now writes `json-as` (`^1.3.6`) into the consumer's `devDependencies` so a fresh project installs everything it needs in one step.
16
+ - chore: `ast init` now writes `json-as` (`^1.3.5`) into the consumer's `devDependencies` so a fresh project installs everything it needs in one step.
17
+ - fix: align the `covered, missing` column in coverage file breakdowns so long file paths no longer push the counts out of column.
18
+ - feat: `--show-coverage` (and `--show-coverage=all`) now auto-enable coverage when coverage hasn't been explicitly toggled, removing the "coverage is disabled" warning when only the show flag is passed.
6
19
 
7
20
  ## 2026-05-18 - v1.1.7
8
21
 
@@ -14,7 +27,7 @@
14
27
  ### Runtime
15
28
 
16
29
  - chore: replace the homegrown JSON serialization helpers (`quote`, `rawOrNull`, `stringifyValue`, `escape`, `unicodeEscape`, `stringifyArray`) with `json-as` across the AssemblyScript runtime and transform, and delete `assembly/util/json.ts`. The `LogTransform` now injects `import { JSON } from "json-as/assembly"` per instrumented source and inlines `JSON.stringify<T>()` into the log helper.
17
- - chore: promote `json-as` to a required peer dependency (`>=1.0.0`). npm 7+ installs it automatically; pnpm and yarn users must add `json-as` to their own `devDependencies` alongside `as-test`.
30
+ - chore: promote `json-as` to a required peer dependency (`>=1.3.5`, the first version compatible with the AS NodeKind tuple changes used here). npm 7+ installs it automatically; pnpm and yarn users must add `json-as` to their own `devDependencies` alongside `as-test`.
18
31
  - chore: remove the unused `__as_test_log_default` and `__as_test_json_value` exports.
19
32
 
20
33
  ## 2026-05-14 - v1.1.6
@@ -0,0 +1,13 @@
1
+ import { expect, fuzz, FuzzSeed } from "as-test";
2
+
3
+ fuzz(
4
+ "nested array.fuzz: index windows stay ordered",
5
+ (start: i32, end: i32): bool => {
6
+ expect(start <= end).toBe(true);
7
+ return end - start <= 64;
8
+ },
9
+ ).generate((seed: FuzzSeed, run: (start: i32, end: i32) => bool): void => {
10
+ const start = seed.i32({ min: 0, max: 64 });
11
+ const width = seed.i32({ min: 0, max: 64 });
12
+ run(start, start + width);
13
+ });
@@ -1,4 +1,4 @@
1
- import { existsSync } from "fs";
1
+ import { existsSync, readFileSync } from "fs";
2
2
  import { glob } from "glob";
3
3
  import chalk from "chalk";
4
4
  import { spawn } from "child_process";
@@ -58,11 +58,17 @@ export async function build(
58
58
  ensureDeps(config);
59
59
  }
60
60
  const pkgRunner = getPkgRunner();
61
- const inputPatterns = resolveInputPatterns(config.input, selectors);
61
+ const sourceInputPatterns =
62
+ overrides.kind === "fuzz" ? config.fuzz.input : config.input;
63
+ const inputPatterns = resolveInputPatterns(sourceInputPatterns, selectors);
62
64
  const inputFiles = (await glob(inputPatterns)).sort((a, b) =>
63
65
  a.localeCompare(b),
64
66
  );
65
- const duplicateSpecBasenames = resolveDuplicateBasenames(inputFiles);
67
+ // Disambiguation must consider the entire configured input set, not just the
68
+ // selector-filtered subset, otherwise running `ast test <one-spec>` writes
69
+ // an artifact name the runner won't look up (it always globs full input).
70
+ const duplicateSpecBasenames =
71
+ await resolveAllConfiguredDuplicateBasenames(sourceInputPatterns);
66
72
  const coverageEnabled = resolveCoverageEnabled(
67
73
  config.coverage,
68
74
  featureToggles.coverage,
@@ -181,7 +187,10 @@ export async function getBuildInvocationPreview(
181
187
  if (overrides.args?.length) {
182
188
  config.buildOptions.args = [...config.buildOptions.args, ...overrides.args];
183
189
  }
184
- const duplicateSpecBasenames = resolveDuplicateBasenames([file]);
190
+ const sourceInputPatterns =
191
+ overrides.kind === "fuzz" ? config.fuzz.input : config.input;
192
+ const duplicateSpecBasenames =
193
+ await resolveAllConfiguredDuplicateBasenames(sourceInputPatterns);
185
194
  const outFile = `${config.outDir}/${resolveArtifactFileName(file, config.buildOptions.target, modeName, duplicateSpecBasenames)}`;
186
195
  return getBuildCommand(
187
196
  config,
@@ -218,7 +227,10 @@ export async function getBuildReuseInfo(
218
227
  if (hasCustomBuildCommand(config)) {
219
228
  return null;
220
229
  }
221
- const duplicateSpecBasenames = resolveDuplicateBasenames([file]);
230
+ const sourceInputPatterns =
231
+ overrides.kind === "fuzz" ? config.fuzz.input : config.input;
232
+ const duplicateSpecBasenames =
233
+ await resolveAllConfiguredDuplicateBasenames(sourceInputPatterns);
222
234
  const outFile = `${config.outDir}/${resolveArtifactFileName(file, config.buildOptions.target, modeName, duplicateSpecBasenames)}`;
223
235
  const invocation = getBuildCommand(
224
236
  config,
@@ -368,6 +380,11 @@ function resolveArtifactFileName(
368
380
  const stem = ext.length ? legacy.slice(0, -ext.length) : legacy;
369
381
  return `${stem}.${disambiguator}${ext}`;
370
382
  }
383
+ async function resolveAllConfiguredDuplicateBasenames(configured) {
384
+ const patterns = Array.isArray(configured) ? configured : [configured];
385
+ const files = await glob(patterns);
386
+ return resolveDuplicateBasenames(files);
387
+ }
371
388
  function resolveDuplicateBasenames(files) {
372
389
  const counts = new Map();
373
390
  for (const file of files) {
@@ -575,9 +592,11 @@ function getDefaultBuildArgs(config, featureToggles) {
575
592
  const buildArgs = [];
576
593
  const tryAsEnabled = resolveTryAsEnabled(featureToggles.tryAs);
577
594
  buildArgs.push("--transform", "as-test/transform");
578
- const jsonAsTransform = resolveProjectModule("json-as/transform");
579
- if (jsonAsTransform) {
580
- buildArgs.push("--transform", jsonAsTransform);
595
+ if (
596
+ resolveProjectModule("json-as/transform") &&
597
+ !userSuppliesJsonAsTransform(config)
598
+ ) {
599
+ buildArgs.push("--transform", "json-as/transform");
581
600
  }
582
601
  if (tryAsEnabled) {
583
602
  buildArgs.push("--transform", "try-as/transform");
@@ -618,6 +637,74 @@ function getDefaultBuildArgs(config, featureToggles) {
618
637
  }
619
638
  return buildArgs;
620
639
  }
640
+ // Treats anything whose path contains a "json-as" path component as a
641
+ // user-supplied json-as transform. Matches bare specifiers, subpath specifiers,
642
+ // absolute paths, and ./node_modules paths.
643
+ const JSON_AS_TRANSFORM_PATTERN = /(?:^|[\\/])json-as(?:[\\/@]|$)/;
644
+ function userSuppliesJsonAsTransform(config) {
645
+ for (const raw of config.buildOptions.args) {
646
+ if (!raw.length) continue;
647
+ const tokens = tokenizeCommand(raw);
648
+ for (let i = 0; i < tokens.length; i++) {
649
+ const token = tokens[i];
650
+ if (token == "--transform") {
651
+ const value = tokens[i + 1];
652
+ if (value && JSON_AS_TRANSFORM_PATTERN.test(value)) return true;
653
+ } else if (token.startsWith("--transform=")) {
654
+ const value = token.slice("--transform=".length);
655
+ if (value && JSON_AS_TRANSFORM_PATTERN.test(value)) return true;
656
+ }
657
+ }
658
+ }
659
+ if (config.config && config.config !== "none" && existsSync(config.config)) {
660
+ if (asconfigDeclaresJsonAs(config.config, new Set())) return true;
661
+ }
662
+ return false;
663
+ }
664
+ function asconfigDeclaresJsonAs(configFile, seen) {
665
+ const resolved = path.resolve(configFile);
666
+ if (seen.has(resolved)) return false;
667
+ seen.add(resolved);
668
+ let parsed;
669
+ try {
670
+ parsed = JSON.parse(readFileSync(resolved, "utf8"));
671
+ } catch {
672
+ return false;
673
+ }
674
+ if (!parsed || typeof parsed != "object") return false;
675
+ const obj = parsed;
676
+ if (transformsContainJsonAs(obj.options)) return true;
677
+ if (transformsContainJsonAs(obj)) return true;
678
+ const targets = obj.targets;
679
+ if (targets && typeof targets == "object" && !Array.isArray(targets)) {
680
+ for (const value of Object.values(targets)) {
681
+ if (transformsContainJsonAs(value)) return true;
682
+ }
683
+ }
684
+ const extendsValue = obj.extends;
685
+ if (typeof extendsValue == "string" && extendsValue.length) {
686
+ const parentPath = path.resolve(path.dirname(resolved), extendsValue);
687
+ if (existsSync(parentPath) && asconfigDeclaresJsonAs(parentPath, seen)) {
688
+ return true;
689
+ }
690
+ }
691
+ return false;
692
+ }
693
+ function transformsContainJsonAs(value) {
694
+ if (!value || typeof value != "object") return false;
695
+ const transform = value.transform;
696
+ if (typeof transform == "string") {
697
+ return JSON_AS_TRANSFORM_PATTERN.test(transform);
698
+ }
699
+ if (Array.isArray(transform)) {
700
+ for (const item of transform) {
701
+ if (typeof item == "string" && JSON_AS_TRANSFORM_PATTERN.test(item)) {
702
+ return true;
703
+ }
704
+ }
705
+ }
706
+ return false;
707
+ }
621
708
  function resolveTryAsEnabled(override) {
622
709
  const installed = hasTryAsRuntime();
623
710
  if (override === false) return false;
@@ -626,6 +713,7 @@ function resolveTryAsEnabled(override) {
626
713
  'try-as feature was enabled, but package "try-as" is not installed',
627
714
  );
628
715
  }
716
+ if (override === true) return true;
629
717
  return false;
630
718
  }
631
719
  function resolveCoverageEnabled(rawCoverage, override) {
@@ -29,7 +29,13 @@ export async function fuzz(
29
29
  `No fuzz files matched: ${selectors.length ? selectors.join(", ") : "configured input patterns"}`,
30
30
  );
31
31
  }
32
- const duplicateBasenames = resolveDuplicateBasenames(inputFiles);
32
+ // Disambiguation must consider the full configured fuzz input set, not the
33
+ // selector-filtered subset, so artifact names stay consistent across runs.
34
+ const fullPatterns = Array.isArray(config.input)
35
+ ? config.input
36
+ : [config.input];
37
+ const allFuzzFiles = await glob(fullPatterns);
38
+ const duplicateBasenames = resolveDuplicateBasenames(allFuzzFiles);
33
39
  const results = [];
34
40
  for (const file of inputFiles) {
35
41
  const buildStartedAt = Date.now();
@@ -651,7 +651,7 @@ function applyInit(root, target, example, fuzzExample, force) {
651
651
  devDependencies["as-test"] = "^" + getCliVersion();
652
652
  }
653
653
  if (!hasDependency(pkg, "json-as")) {
654
- devDependencies["json-as"] = "^1.3.6";
654
+ devDependencies["json-as"] = "^1.3.5";
655
655
  }
656
656
  if (!hasDependency(pkg, "assemblyscript")) {
657
657
  devDependencies["assemblyscript"] = "^0.28.9";
package/bin/index.js CHANGED
@@ -247,7 +247,7 @@ function info() {
247
247
  console.log("");
248
248
  console.log(
249
249
  chalk.dim(
250
- "If this tool provides value, please consider sponsoring my open-source work! https://jairus.dev/sponsor",
250
+ "If this tool provides value, please consider sponsoring my open-source work! https://github.com/sponsors/JairusSW",
251
251
  ) + "\n",
252
252
  );
253
253
  console.log(
@@ -734,8 +734,24 @@ function resolveFeatureToggles(rawArgs, command) {
734
734
  }
735
735
  }
736
736
  }
737
+ if (out.coverage === undefined && hasShowCoverageFlag(rawArgs, command)) {
738
+ out.coverage = true;
739
+ }
737
740
  return out;
738
741
  }
742
+ function hasShowCoverageFlag(rawArgs, command) {
743
+ let seenCommand = false;
744
+ for (const arg of rawArgs) {
745
+ if (!seenCommand) {
746
+ if (arg == command) seenCommand = true;
747
+ continue;
748
+ }
749
+ if (arg == "--show-coverage" || arg.startsWith("--show-coverage=")) {
750
+ return true;
751
+ }
752
+ }
753
+ return false;
754
+ }
739
755
  function resolveFuzzOverrides(rawArgs, command) {
740
756
  const out = {};
741
757
  let seenCommand = false;
@@ -1350,7 +1366,8 @@ async function runTestSequential(
1350
1366
  const results = [];
1351
1367
  let failed = false;
1352
1368
  const buildIntervals = [];
1353
- const duplicateSpecBasenames = resolveDuplicateSpecBasenames(files);
1369
+ const duplicateSpecBasenames =
1370
+ await resolveAllConfiguredDuplicateSpecBasenames(configPath);
1354
1371
  for (const file of files) {
1355
1372
  const buildStartedAt = Date.now();
1356
1373
  let result;
@@ -1628,7 +1645,8 @@ async function runRuntimeMatrix(
1628
1645
  failed: false,
1629
1646
  passed: false,
1630
1647
  }));
1631
- const duplicateSpecBasenames = resolveDuplicateSpecBasenames(files);
1648
+ const duplicateSpecBasenames =
1649
+ await resolveAllConfiguredDuplicateSpecBasenames(configPath);
1632
1650
  const buildIntervals = [];
1633
1651
  for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
1634
1652
  const file = files[fileIndex];
@@ -2088,7 +2106,8 @@ async function runTestMatrix(
2088
2106
  failed: false,
2089
2107
  passed: false,
2090
2108
  }));
2091
- const duplicateSpecBasenames = resolveDuplicateSpecBasenames(files);
2109
+ const duplicateSpecBasenames =
2110
+ await resolveAllConfiguredDuplicateSpecBasenames(configPath);
2092
2111
  const buildIntervals = [];
2093
2112
  for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
2094
2113
  const file = files[fileIndex];
@@ -2394,7 +2413,8 @@ async function runRuntimeMatrixParallel(
2394
2413
  const silentReporter = {};
2395
2414
  const modeLabels = modes.map((modeName) => modeName ?? "default");
2396
2415
  const showPerModeTimes = Boolean(runFlags.verbose);
2397
- const duplicateSpecBasenames = resolveDuplicateSpecBasenames(files);
2416
+ const duplicateSpecBasenames =
2417
+ await resolveAllConfiguredDuplicateSpecBasenames(configPath);
2398
2418
  const ordered = new Array(files.length);
2399
2419
  const useQueueDisplay = reporterSession.reporterKind == "default";
2400
2420
  const queueDisplay = new ParallelQueueDisplay(
@@ -2543,7 +2563,8 @@ async function runTestSingleParallel(
2543
2563
  snapshotEnabled,
2544
2564
  createSnapshots: runFlags.createSnapshots,
2545
2565
  });
2546
- const duplicateSpecBasenames = resolveDuplicateSpecBasenames(files);
2566
+ const duplicateSpecBasenames =
2567
+ await resolveAllConfiguredDuplicateSpecBasenames(configPath);
2547
2568
  const results = new Array(files.length);
2548
2569
  const useQueueDisplay = reporterSession.reporterKind == "default";
2549
2570
  const queueDisplay = new ParallelQueueDisplay(
@@ -2713,7 +2734,8 @@ async function runTestMatrixParallel(
2713
2734
  const silentReporter = {};
2714
2735
  const modeLabels = modes.map((modeName) => modeName ?? "default");
2715
2736
  const showPerModeTimes = Boolean(runFlags.verbose);
2716
- const duplicateSpecBasenames = resolveDuplicateSpecBasenames(files);
2737
+ const duplicateSpecBasenames =
2738
+ await resolveAllConfiguredDuplicateSpecBasenames(configPath);
2717
2739
  const ordered = new Array(files.length);
2718
2740
  const useQueueDisplay = reporterSession.reporterKind == "default";
2719
2741
  const queueDisplay = new ParallelQueueDisplay(
@@ -3591,6 +3613,26 @@ function resolveDuplicateSpecBasenames(files) {
3591
3613
  }
3592
3614
  return duplicates;
3593
3615
  }
3616
+ // Disambiguation must consider the full configured input set, not the
3617
+ // selector-filtered subset, otherwise running a single spec writes/looks up an
3618
+ // artifact name that the rest of the toolchain doesn't agree on.
3619
+ async function resolveAllConfiguredDuplicateSpecBasenames(configPath) {
3620
+ const resolvedConfigPath =
3621
+ configPath ?? path.join(process.cwd(), "./as-test.config.json");
3622
+ const config = loadConfig(resolvedConfigPath, false);
3623
+ return resolveDuplicateBasenamesForPatterns(config.input);
3624
+ }
3625
+ async function resolveAllConfiguredDuplicateFuzzBasenames(configPath) {
3626
+ const resolvedConfigPath =
3627
+ configPath ?? path.join(process.cwd(), "./as-test.config.json");
3628
+ const config = loadConfig(resolvedConfigPath, false);
3629
+ return resolveDuplicateBasenamesForPatterns(config.fuzz.input);
3630
+ }
3631
+ async function resolveDuplicateBasenamesForPatterns(configured) {
3632
+ const patterns = Array.isArray(configured) ? configured : [configured];
3633
+ const files = await glob(patterns);
3634
+ return resolveDuplicateSpecBasenames(files);
3635
+ }
3594
3636
  function resolvePerFileArtifactKey(file, duplicateSpecBasenames) {
3595
3637
  const base = path.basename(file);
3596
3638
  let raw = base;
@@ -4159,8 +4201,10 @@ async function listExecutionPlan(
4159
4201
  : `No test files matched: ${scope}`,
4160
4202
  );
4161
4203
  }
4162
- const duplicateSpecBasenames = resolveDuplicateSpecBasenames(specFiles);
4163
- const duplicateFuzzBasenames = resolveDuplicateSpecBasenames(fuzzFiles);
4204
+ const duplicateSpecBasenames =
4205
+ await resolveAllConfiguredDuplicateSpecBasenames(configPath);
4206
+ const duplicateFuzzBasenames =
4207
+ await resolveAllConfiguredDuplicateFuzzBasenames(configPath);
4164
4208
  if (specFiles.length) {
4165
4209
  process.stdout.write(chalk.bold("Resolved files:\n"));
4166
4210
  for (const file of specFiles) {
@@ -897,7 +897,12 @@ function renderCoverageSummary(summary, showCoverage) {
897
897
  return a.file.localeCompare(b.file);
898
898
  });
899
899
  console.log(chalk.bold(" File Breakdown"));
900
- for (const file of ranked.slice(0, 8)) {
900
+ const displayed = ranked.slice(0, 8);
901
+ const fileNameWidth = displayed.reduce(
902
+ (max, file) => Math.max(max, toRelativeResultPath(file.file).length),
903
+ 0,
904
+ );
905
+ for (const file of displayed) {
901
906
  const filePct = file.total
902
907
  ? ((file.covered * 100) / file.total).toFixed(2)
903
908
  : "100.00";
@@ -910,11 +915,11 @@ function renderCoverageSummary(summary, showCoverage) {
910
915
  const suffix =
911
916
  file.uncovered > 0 ? `${file.uncovered} missing` : "fully covered";
912
917
  console.log(
913
- ` ${fileColor(filePct.padStart(6) + "%")} ${toRelativeResultPath(file.file).padEnd(36)} ${chalk.dim(`${file.covered}/${file.total} covered, ${suffix}`)}`,
918
+ ` ${fileColor(filePct.padStart(6) + "%")} ${toRelativeResultPath(file.file).padEnd(fileNameWidth)} ${chalk.dim(`${file.covered}/${file.total} covered, ${suffix}`)}`,
914
919
  );
915
920
  }
916
921
  if (ranked.length > 8) {
917
- console.log(chalk.dim(` ... ${ranked.length - 8} more files`));
922
+ console.log(chalk.dim(` ... ${ranked.length - 8} more files`));
918
923
  }
919
924
  }
920
925
  function renderCoveragePoints(files, expandNested) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "as-test",
3
- "version": "1.1.8",
3
+ "version": "1.1.10",
4
4
  "author": "Jairus Tanaka",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,7 +13,7 @@
13
13
  "wipc-js": "^0.1.1"
14
14
  },
15
15
  "peerDependencies": {
16
- "json-as": ">=1.0.0"
16
+ "json-as": ">=1.3.5"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@assemblyscript/wasi-shim": "^0.1.0",
@@ -75,7 +75,8 @@
75
75
  "access": "public"
76
76
  },
77
77
  "scripts": {
78
- "test": "node ./bin/index.js test --parallel",
78
+ "test": "npm run test:as && npm run test:integration",
79
+ "test:as": "node ./bin/index.js test --parallel",
79
80
  "test:integration": "npm run build:cli && npm run build:lib && node --test tests/*.test.mjs",
80
81
  "test:ci": "node ./bin/index.js test --parallel --tap --config ./as-test.ci.config.json",
81
82
  "fuzz": "node ./bin/index.js fuzz",
@@ -96,8 +97,8 @@
96
97
  "docs:build": "vitepress build docs",
97
98
  "docs:preview": "vitepress preview docs",
98
99
  "format": "prettier -w .",
99
- "release:check": "npm run build:cli && npm run build:lib && npm run build:transform && npm run test && npm run test:integration && npm run test:examples && npm pack --dry-run --cache /tmp/as-test-npm-cache",
100
- "prepublishOnly": "npm run build:cli && npm run build:lib && npm run build:transform && npm run test && npm run test:integration && npm run format"
100
+ "release:check": "npm run build:cli && npm run build:lib && npm run build:transform && npm run test && npm run test:examples && npm pack --dry-run --cache /tmp/as-test-npm-cache",
101
+ "prepublishOnly": "npm run build:cli && npm run build:lib && npm run build:transform && npm run test && npm run format"
101
102
  },
102
103
  "type": "module"
103
104
  }