ttsc 0.4.3-dev.20260426-3 → 0.4.4-dev.20260426

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.
@@ -76,8 +76,8 @@ which resolve the consuming project's @typescript/native-preview binary and any
76
76
  plugin-selected native sidecar.
77
77
 
78
78
  Usage:
79
- ttsc-platform --version
80
- ttsc-platform demo --type=string
79
+ ttsc --version
80
+ ttsc demo --type=string
81
81
  `))
82
82
  }
83
83
 
package/lib/api.d.ts CHANGED
@@ -66,6 +66,7 @@ export type CheckOptions = Omit<BuildOptions, "emit">;
66
66
  export declare function transform(options: TransformOptions): string;
67
67
  /** Result of `build()`. Non-zero `status` means the build failed. */
68
68
  export interface BuildResult {
69
+ emittedFiles?: string[];
69
70
  status: number;
70
71
  stdout: string;
71
72
  stderr: string;
package/lib/api.js CHANGED
@@ -122,6 +122,9 @@ function transform(options) {
122
122
  const sourceFile = realpathIfExists(path.isAbsolute(options.file)
123
123
  ? options.file
124
124
  : path.resolve(options.cwd ?? process.cwd(), options.file));
125
+ if (execution.sourcePlugins.length > 0) {
126
+ return transformWithSourceTransforms(options, execution, sourceFile);
127
+ }
125
128
  if (execution.nativeBinary) {
126
129
  return transformWithNativeBinary(options, execution, sourceFile);
127
130
  }
@@ -147,8 +150,9 @@ function transform(options) {
147
150
  if (!emitted) {
148
151
  throw new Error(`ttsc.transform: no output produced for ${sourceFile}`);
149
152
  }
150
- const transformed = finalizeTransformText(execution.plugins, {
153
+ const transformed = finalizeTransformText(execution.outputPlugins, {
151
154
  command: "transform",
155
+ compilerOptions: execution.compilerOptions,
152
156
  cwd: execution.cwd,
153
157
  projectRoot: execution.projectRoot,
154
158
  sourceFile,
@@ -185,8 +189,9 @@ function transformWithNativeBinary(options, execution, sourceFile) {
185
189
  if (res.status !== 0) {
186
190
  throw new Error("ttsc.transform exited " + res.status + "\n" + (res.stderr || ""));
187
191
  }
188
- const transformed = finalizeTransformText(execution.plugins, {
192
+ const transformed = finalizeTransformText(execution.outputPlugins, {
189
193
  command: "transform",
194
+ compilerOptions: execution.compilerOptions,
190
195
  cwd: execution.cwd,
191
196
  projectRoot: execution.projectRoot,
192
197
  sourceFile,
@@ -198,6 +203,58 @@ function transformWithNativeBinary(options, execution, sourceFile) {
198
203
  }
199
204
  return transformed;
200
205
  }
206
+ function transformWithSourceTransforms(options, execution, sourceFile) {
207
+ if (execution.nativeBinary || execution.nativeMode !== "none") {
208
+ throw new Error("ttsc.transform: transformSource cannot be combined with native rewrite mode yet");
209
+ }
210
+ const materialized = materializeSourceTransformedProject(execution, "transform", sourceFile);
211
+ const tempOutDir = path.join(materialized.root, ".ttsc-transform-out");
212
+ try {
213
+ const tempSourceFile = toMaterializedPath(sourceFile, materialized);
214
+ const result = build({
215
+ ...options,
216
+ cwd: materialized.root,
217
+ emit: true,
218
+ forceListEmittedFiles: true,
219
+ outDir: tempOutDir,
220
+ plugins: false,
221
+ tsconfig: materialized.tsconfig,
222
+ });
223
+ if (result.status !== 0) {
224
+ throw new Error("ttsc.transform exited " +
225
+ result.status +
226
+ "\n" +
227
+ (result.stderr || result.stdout));
228
+ }
229
+ const emitted = findEmittedFile(tempOutDir, materialized.root, tempSourceFile);
230
+ if (!emitted) {
231
+ throw new Error(`ttsc.transform: no output produced for ${sourceFile}`);
232
+ }
233
+ let transformed = finalizeTransformText(execution.outputPlugins, {
234
+ command: "transform",
235
+ compilerOptions: execution.compilerOptions,
236
+ cwd: execution.cwd,
237
+ projectRoot: execution.projectRoot,
238
+ sourceFile,
239
+ tsconfig: execution.tsconfig,
240
+ }, fs.readFileSync(emitted, "utf8"));
241
+ if (options.out) {
242
+ const mapFile = `${emitted}.map`;
243
+ if (fs.existsSync(mapFile)) {
244
+ const outMap = `${options.out}.map`;
245
+ fs.mkdirSync(path.dirname(outMap), { recursive: true });
246
+ fs.writeFileSync(outMap, patchSourceMapText(fs.readFileSync(mapFile, "utf8"), materialized, outMap, mapFile), "utf8");
247
+ transformed = rewriteSourceMapReference(transformed, path.basename(outMap));
248
+ }
249
+ fs.mkdirSync(path.dirname(options.out), { recursive: true });
250
+ fs.writeFileSync(options.out, transformed, "utf8");
251
+ }
252
+ return transformed;
253
+ }
254
+ finally {
255
+ fs.rmSync(materialized.root, { recursive: true, force: true });
256
+ }
257
+ }
201
258
  function realpathIfExists(file) {
202
259
  try {
203
260
  return fs.realpathSync(file);
@@ -213,6 +270,9 @@ function realpathIfExists(file) {
213
270
  */
214
271
  function build(options = {}) {
215
272
  const execution = resolveExecutionContext(options);
273
+ if (execution.sourcePlugins.length > 0) {
274
+ return buildWithSourceTransforms(options, execution);
275
+ }
216
276
  if (execution.nativeBinary) {
217
277
  return buildWithNativeBinary(options, execution);
218
278
  }
@@ -231,7 +291,8 @@ function build(options = {}) {
231
291
  }
232
292
  }
233
293
  const args = createTsgoBuildArgs(execution, options, {
234
- listEmittedFiles: options.emit !== false && execution.plugins.length > 0,
294
+ listEmittedFiles: options.emit !== false &&
295
+ (execution.outputPlugins.length > 0 || options.forceListEmittedFiles === true),
235
296
  });
236
297
  const res = spawnBinary(execution.tsgo.binary, args, {
237
298
  cwd: execution.projectRoot,
@@ -253,10 +314,10 @@ function build(options = {}) {
253
314
  if (emittedFiles.length !== 0) {
254
315
  result.stdout = stripEmittedFileLines(result.stdout);
255
316
  }
256
- if (result.status === 0 && options.emit !== false && execution.plugins.length > 0) {
257
- applyBuildPlugins(execution.plugins, execution, emittedFiles);
317
+ if (result.status === 0 && options.emit !== false && execution.outputPlugins.length > 0) {
318
+ applyBuildPlugins(execution.outputPlugins, execution, emittedFiles);
258
319
  }
259
- return normalizeFailedDiagnostics(result);
320
+ return normalizeFailedDiagnostics({ ...result, emittedFiles });
260
321
  }
261
322
  function buildWithNativeBinary(options, execution) {
262
323
  const args = createNativeBuildArgs(execution, options);
@@ -277,6 +338,38 @@ function buildWithNativeBinary(options, execution) {
277
338
  stderr: outputText(res.stderr),
278
339
  });
279
340
  }
341
+ function buildWithSourceTransforms(options, execution) {
342
+ if (execution.nativeBinary || execution.nativeMode !== "none") {
343
+ return {
344
+ status: 2,
345
+ stdout: "",
346
+ stderr: "ttsc.build: transformSource cannot be combined with native rewrite mode yet\n",
347
+ };
348
+ }
349
+ const materialized = materializeSourceTransformedProject(execution, "build");
350
+ try {
351
+ const outDir = mapOutDirToMaterializedProject(options.outDir, execution, materialized);
352
+ const result = build({
353
+ ...options,
354
+ cwd: materialized.root,
355
+ forceListEmittedFiles: true,
356
+ outDir,
357
+ plugins: false,
358
+ tsconfig: materialized.tsconfig,
359
+ });
360
+ if (result.status === 0 && options.emit !== false) {
361
+ const copied = copyMaterializedEmittedFiles(materialized, result.emittedFiles ?? []);
362
+ result.emittedFiles = copied;
363
+ if (execution.outputPlugins.length > 0) {
364
+ applyBuildPlugins(execution.outputPlugins, execution, copied);
365
+ }
366
+ }
367
+ return result;
368
+ }
369
+ finally {
370
+ fs.rmSync(materialized.root, { recursive: true, force: true });
371
+ }
372
+ }
280
373
  /**
281
374
  * Run `ttsc check` (build without emit) — CI gate / pre-commit hook use.
282
375
  * Resolves with an exit-code record; does not throw.
@@ -374,11 +467,13 @@ function resolveExecutionContext(options) {
374
467
  tsconfig,
375
468
  });
376
469
  return {
470
+ compilerOptions: loaded.project.compilerOptions,
377
471
  cwd,
378
472
  nativeBinary: loaded.nativeBinary ?? null,
379
473
  nativeMode: options.rewriteMode ?? loaded.nativeMode,
380
- plugins: loaded.plugins.filter((plugin) => plugin.transformOutput),
474
+ outputPlugins: loaded.plugins.filter((plugin) => plugin.transformOutput),
381
475
  projectRoot,
476
+ sourcePlugins: loaded.plugins.filter((plugin) => plugin.transformSource),
382
477
  tsgo,
383
478
  tsconfig,
384
479
  };
@@ -404,6 +499,7 @@ function applyBuildPlugins(plugins, execution, emittedFiles) {
404
499
  const next = (0, plugin_1.applyPluginTransforms)(plugins, {
405
500
  code: current,
406
501
  command: "build",
502
+ compilerOptions: execution.compilerOptions,
407
503
  cwd: execution.cwd,
408
504
  outputFile: file,
409
505
  projectRoot: execution.projectRoot,
@@ -442,6 +538,7 @@ function normalizeFailedDiagnostics(result) {
442
538
  return result;
443
539
  }
444
540
  return {
541
+ emittedFiles: result.emittedFiles,
445
542
  status: result.status,
446
543
  stdout: "",
447
544
  stderr: result.stdout,
@@ -514,4 +611,408 @@ function readOwnPackageVersion() {
514
611
  return "0.0.0";
515
612
  }
516
613
  }
614
+ function materializeSourceTransformedProject(execution, command, onlySourceFile) {
615
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "ttsc-source-"));
616
+ const materialized = {
617
+ mappers: new Map(),
618
+ originalRoot: execution.projectRoot,
619
+ root,
620
+ tsconfig: path.join(root, path.relative(execution.projectRoot, execution.tsconfig)),
621
+ };
622
+ copyProjectForSourceTransforms(execution.projectRoot, root, execution.compilerOptions);
623
+ const files = onlySourceFile
624
+ ? [toMaterializedPath(onlySourceFile, materialized)]
625
+ : listSourceTransformFiles(root);
626
+ for (const tempFile of files) {
627
+ if (!fs.existsSync(tempFile) || !fs.statSync(tempFile).isFile()) {
628
+ continue;
629
+ }
630
+ const originalFile = fromMaterializedPath(tempFile, materialized);
631
+ const current = fs.readFileSync(tempFile, "utf8");
632
+ const transformed = (0, plugin_1.applyPluginSourceTransformsWithMap)(execution.sourcePlugins, {
633
+ code: current,
634
+ command,
635
+ compilerOptions: execution.compilerOptions,
636
+ cwd: execution.cwd,
637
+ projectRoot: execution.projectRoot,
638
+ sourceFile: originalFile,
639
+ tsconfig: execution.tsconfig,
640
+ });
641
+ const next = transformed.code;
642
+ if (next !== current) {
643
+ fs.writeFileSync(tempFile, next, "utf8");
644
+ }
645
+ if (transformed.stages.length > 0) {
646
+ materialized.mappers.set(filepathKey(tempFile), {
647
+ finalCode: next,
648
+ originalCode: current,
649
+ stages: transformed.stages,
650
+ });
651
+ }
652
+ }
653
+ return materialized;
654
+ }
655
+ function copyProjectForSourceTransforms(source, target, compilerOptions) {
656
+ const excluded = new Set([".git", "node_modules"]);
657
+ const outDir = typeof compilerOptions.outDir === "string" ? compilerOptions.outDir : "";
658
+ const resolvedOutDir = outDir ? path.resolve(outDir) : "";
659
+ copyDirectoryFiltered(source, target, (entry) => {
660
+ if (excluded.has(path.basename(entry))) {
661
+ return false;
662
+ }
663
+ if (resolvedOutDir && isPathInside(entry, resolvedOutDir)) {
664
+ return false;
665
+ }
666
+ return true;
667
+ });
668
+ const nodeModules = path.join(source, "node_modules");
669
+ if (fs.existsSync(nodeModules)) {
670
+ const targetNodeModules = path.join(target, "node_modules");
671
+ try {
672
+ fs.symlinkSync(nodeModules, targetNodeModules, "junction");
673
+ }
674
+ catch {
675
+ copyDirectoryFiltered(nodeModules, targetNodeModules, () => true);
676
+ }
677
+ }
678
+ }
679
+ function copyDirectoryFiltered(source, target, shouldCopy) {
680
+ if (!shouldCopy(source)) {
681
+ return;
682
+ }
683
+ const stat = fs.lstatSync(source);
684
+ if (stat.isSymbolicLink()) {
685
+ const link = fs.readlinkSync(source);
686
+ fs.symlinkSync(link, target);
687
+ return;
688
+ }
689
+ if (stat.isDirectory()) {
690
+ fs.mkdirSync(target, { recursive: true });
691
+ for (const entry of fs.readdirSync(source)) {
692
+ copyDirectoryFiltered(path.join(source, entry), path.join(target, entry), shouldCopy);
693
+ }
694
+ return;
695
+ }
696
+ if (stat.isFile()) {
697
+ fs.mkdirSync(path.dirname(target), { recursive: true });
698
+ fs.copyFileSync(source, target);
699
+ }
700
+ }
701
+ function listSourceTransformFiles(root) {
702
+ const out = [];
703
+ const stack = [root];
704
+ while (stack.length !== 0) {
705
+ const current = stack.pop();
706
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
707
+ if (entry.name === "node_modules" || entry.name === ".git") {
708
+ continue;
709
+ }
710
+ const next = path.join(current, entry.name);
711
+ if (entry.isDirectory()) {
712
+ stack.push(next);
713
+ }
714
+ else if (entry.isFile() && isTransformableSource(next)) {
715
+ out.push(next);
716
+ }
717
+ }
718
+ }
719
+ return out;
720
+ }
721
+ function isTransformableSource(file) {
722
+ return /\.(?:[cm]?tsx?)$/i.test(file) && !/\.d\.[cm]?ts$/i.test(file);
723
+ }
724
+ function mapOutDirToMaterializedProject(outDir, execution, materialized) {
725
+ if (!outDir) {
726
+ return undefined;
727
+ }
728
+ const resolved = path.resolve(execution.cwd, outDir);
729
+ if (isPathInside(resolved, execution.projectRoot)) {
730
+ return toMaterializedPath(resolved, materialized);
731
+ }
732
+ return path.join(materialized.root, ".ttsc-out");
733
+ }
734
+ function copyMaterializedEmittedFiles(materialized, emittedFiles) {
735
+ const copied = [];
736
+ for (const emitted of emittedFiles) {
737
+ if (!isPathInside(emitted, materialized.root)) {
738
+ continue;
739
+ }
740
+ const target = fromMaterializedPath(emitted, materialized);
741
+ fs.mkdirSync(path.dirname(target), { recursive: true });
742
+ if (/\.map$/i.test(emitted)) {
743
+ fs.writeFileSync(target, patchSourceMapText(fs.readFileSync(emitted, "utf8"), materialized, target), "utf8");
744
+ }
745
+ else {
746
+ fs.copyFileSync(emitted, target);
747
+ }
748
+ copied.push(target);
749
+ }
750
+ return copied;
751
+ }
752
+ function toMaterializedPath(file, materialized) {
753
+ const relative = path.relative(materialized.originalRoot, file);
754
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
755
+ return file;
756
+ }
757
+ return path.join(materialized.root, relative);
758
+ }
759
+ function fromMaterializedPath(file, materialized) {
760
+ const relative = path.relative(materialized.root, file);
761
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
762
+ return file;
763
+ }
764
+ return path.join(materialized.originalRoot, relative);
765
+ }
766
+ function isPathInside(file, parent) {
767
+ const relative = path.relative(parent, file);
768
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
769
+ }
770
+ function filepathKey(file) {
771
+ return path.resolve(file).replace(/\\/g, "/");
772
+ }
773
+ function patchSourceMapText(text, materialized, outputFile, tempOutputFile = toMaterializedPath(outputFile, materialized)) {
774
+ let map;
775
+ try {
776
+ map = JSON.parse(text);
777
+ }
778
+ catch {
779
+ return text;
780
+ }
781
+ if (!Array.isArray(map.sources)) {
782
+ return text;
783
+ }
784
+ const tempMapDir = path.dirname(tempOutputFile);
785
+ const originalMapDir = path.dirname(outputFile);
786
+ const nextSources = [];
787
+ const nextSourcesContent = Array.isArray(map.sourcesContent)
788
+ ? [...map.sourcesContent]
789
+ : undefined;
790
+ const sourceMappings = new Map();
791
+ map.sources.forEach((source, index) => {
792
+ const tempSource = path.isAbsolute(source)
793
+ ? source
794
+ : path.resolve(tempMapDir, source);
795
+ if (isPathInside(tempSource, materialized.root)) {
796
+ const originalSource = fromMaterializedPath(tempSource, materialized);
797
+ const mapper = materialized.mappers.get(filepathKey(tempSource));
798
+ if (mapper) {
799
+ sourceMappings.set(index, mapper);
800
+ }
801
+ nextSources.push(relativeSourceMapPath(originalMapDir, originalSource));
802
+ if (nextSourcesContent) {
803
+ try {
804
+ nextSourcesContent[index] = fs.readFileSync(originalSource, "utf8");
805
+ }
806
+ catch {
807
+ /* keep emitted sourcesContent */
808
+ }
809
+ }
810
+ }
811
+ else {
812
+ nextSources.push(source);
813
+ }
814
+ });
815
+ if (sourceMappings.size > 0 && typeof map.mappings === "string") {
816
+ map.mappings = remapSourceMapMappings(map.mappings, sourceMappings);
817
+ }
818
+ map.sources = nextSources;
819
+ if (nextSourcesContent) {
820
+ map.sourcesContent = nextSourcesContent;
821
+ }
822
+ delete map.sourceRoot;
823
+ return JSON.stringify(map);
824
+ }
825
+ function relativeSourceMapPath(fromDir, file) {
826
+ const relative = path.relative(fromDir, file).replace(/\\/g, "/");
827
+ return relative.startsWith(".") ? relative : `./${relative}`;
828
+ }
829
+ function rewriteSourceMapReference(code, mapFileName) {
830
+ const reference = `//# sourceMappingURL=${mapFileName}`;
831
+ if (/\/\/# sourceMappingURL=.*(?:\r?\n)?$/m.test(code)) {
832
+ return code.replace(/\/\/# sourceMappingURL=.*(?:\r?\n)?$/m, `${reference}\n`);
833
+ }
834
+ return code.endsWith("\n") ? `${code}${reference}\n` : `${code}\n${reference}\n`;
835
+ }
836
+ function remapSourceMapMappings(mappings, sourceMappings) {
837
+ const decoded = decodeMappings(mappings);
838
+ for (const line of decoded) {
839
+ for (const segment of line) {
840
+ if (segment.length < 4) {
841
+ continue;
842
+ }
843
+ const mapper = sourceMappings.get(segment[1]);
844
+ if (!mapper) {
845
+ continue;
846
+ }
847
+ const mapped = mapTransformedPositionToOriginal(mapper, {
848
+ column: segment[3],
849
+ line: segment[2],
850
+ });
851
+ segment[2] = mapped.line;
852
+ segment[3] = mapped.column;
853
+ }
854
+ }
855
+ return encodeMappings(decoded);
856
+ }
857
+ function mapTransformedPositionToOriginal(mapper, position) {
858
+ let offset = lineColumnToOffset(mapper.finalCode, position.line, position.column);
859
+ for (let index = mapper.stages.length - 1; index >= 0; index -= 1) {
860
+ offset = mapOffsetToPreviousStage(offset, mapper.stages[index]);
861
+ }
862
+ return offsetToLineColumn(mapper.originalCode, offset);
863
+ }
864
+ function mapOffsetToPreviousStage(offset, stage) {
865
+ let delta = 0;
866
+ for (const edit of stage.edits) {
867
+ if (offset < edit.newStart) {
868
+ return clampOffset(offset - delta, stage.before.length);
869
+ }
870
+ if (offset < edit.newEnd) {
871
+ return edit.start;
872
+ }
873
+ delta += edit.code.length - (edit.end - edit.start);
874
+ }
875
+ return clampOffset(offset - delta, stage.before.length);
876
+ }
877
+ function lineColumnToOffset(source, line, column) {
878
+ const starts = lineStarts(source);
879
+ const start = starts[Math.min(Math.max(line, 0), starts.length - 1)] ?? 0;
880
+ return clampOffset(start + Math.max(column, 0), source.length);
881
+ }
882
+ function offsetToLineColumn(source, offset) {
883
+ const starts = lineStarts(source);
884
+ const clamped = clampOffset(offset, source.length);
885
+ let low = 0;
886
+ let high = starts.length - 1;
887
+ while (low <= high) {
888
+ const mid = (low + high) >> 1;
889
+ const start = starts[mid];
890
+ const next = starts[mid + 1] ?? Number.POSITIVE_INFINITY;
891
+ if (clamped < start) {
892
+ high = mid - 1;
893
+ }
894
+ else if (clamped >= next) {
895
+ low = mid + 1;
896
+ }
897
+ else {
898
+ return { column: clamped - start, line: mid };
899
+ }
900
+ }
901
+ const last = starts.length - 1;
902
+ return { column: clamped - (starts[last] ?? 0), line: last };
903
+ }
904
+ function lineStarts(source) {
905
+ const starts = [0];
906
+ for (let index = 0; index < source.length; index += 1) {
907
+ const ch = source.charCodeAt(index);
908
+ if (ch === 13 /* \r */) {
909
+ if (source.charCodeAt(index + 1) === 10 /* \n */) {
910
+ index += 1;
911
+ }
912
+ starts.push(index + 1);
913
+ }
914
+ else if (ch === 10 /* \n */) {
915
+ starts.push(index + 1);
916
+ }
917
+ }
918
+ return starts;
919
+ }
920
+ function clampOffset(offset, length) {
921
+ return Math.min(Math.max(offset, 0), length);
922
+ }
923
+ const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
924
+ const BASE64_VALUES = new Map([...BASE64_CHARS].map((char, index) => [char, index]));
925
+ function decodeMappings(mappings) {
926
+ const lines = [];
927
+ let line = [];
928
+ let segment = [];
929
+ let index = 0;
930
+ const state = [0, 0, 0, 0, 0];
931
+ while (index < mappings.length) {
932
+ const char = mappings[index];
933
+ if (char === ";") {
934
+ if (segment.length > 0) {
935
+ line.push(segment);
936
+ segment = [];
937
+ }
938
+ lines.push(line);
939
+ line = [];
940
+ state[0] = 0;
941
+ index += 1;
942
+ continue;
943
+ }
944
+ if (char === ",") {
945
+ if (segment.length > 0) {
946
+ line.push(segment);
947
+ segment = [];
948
+ }
949
+ index += 1;
950
+ continue;
951
+ }
952
+ const read = readVlq(mappings, index);
953
+ index = read.next;
954
+ const field = segment.length;
955
+ state[field] = (state[field] ?? 0) + read.value;
956
+ segment.push(state[field]);
957
+ }
958
+ if (segment.length > 0) {
959
+ line.push(segment);
960
+ }
961
+ lines.push(line);
962
+ return lines;
963
+ }
964
+ function encodeMappings(lines) {
965
+ const state = [0, 0, 0, 0, 0];
966
+ return lines
967
+ .map((line) => {
968
+ state[0] = 0;
969
+ return line
970
+ .map((segment) => segment
971
+ .map((value, index) => {
972
+ const relative = value - (state[index] ?? 0);
973
+ state[index] = value;
974
+ return writeVlq(relative);
975
+ })
976
+ .join(""))
977
+ .join(",");
978
+ })
979
+ .join(";");
980
+ }
981
+ function readVlq(input, start) {
982
+ let index = start;
983
+ let shift = 0;
984
+ let value = 0;
985
+ while (index < input.length) {
986
+ const digit = BASE64_VALUES.get(input[index]);
987
+ if (digit === undefined) {
988
+ throw new Error(`ttsc: invalid source map VLQ digit ${input[index]}`);
989
+ }
990
+ index += 1;
991
+ const continuation = (digit & 32) !== 0;
992
+ value += (digit & 31) << shift;
993
+ shift += 5;
994
+ if (!continuation) {
995
+ const negative = (value & 1) === 1;
996
+ const decoded = value >> 1;
997
+ return { next: index, value: negative ? -decoded : decoded };
998
+ }
999
+ }
1000
+ throw new Error("ttsc: unterminated source map VLQ segment");
1001
+ }
1002
+ function writeVlq(value) {
1003
+ let vlq = Math.abs(value) << 1;
1004
+ if (value < 0) {
1005
+ vlq |= 1;
1006
+ }
1007
+ let out = "";
1008
+ do {
1009
+ let digit = vlq & 31;
1010
+ vlq >>>= 5;
1011
+ if (vlq > 0) {
1012
+ digit |= 32;
1013
+ }
1014
+ out += BASE64_CHARS[digit];
1015
+ } while (vlq > 0);
1016
+ return out;
1017
+ }
517
1018
  //# sourceMappingURL=api.js.map