@abaplint/transpiler-cli 2.14.1 → 2.14.3

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/build/bundle.js CHANGED
@@ -71,6 +71,7 @@ class TranspilerConfig {
71
71
  input_folder: "src",
72
72
  input_filter: [],
73
73
  output_folder: "output",
74
+ incremental_output: false,
74
75
  libs: [
75
76
  { "url": "https://github.com/open-abap/open-abap-core" },
76
77
  ],
@@ -314,14 +315,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
314
315
  return (mod && mod.__esModule) ? mod : { "default": mod };
315
316
  };
316
317
  Object.defineProperty(exports, "__esModule", ({ value: true }));
317
- const fs = __importStar(__webpack_require__(/*! fs */ "fs"));
318
- const path = __importStar(__webpack_require__(/*! path */ "path"));
319
318
  const progress_1 = __importDefault(__webpack_require__(/*! progress */ "./node_modules/progress/index.js"));
320
319
  const Transpiler = __importStar(__webpack_require__(/*! @abaplint/transpiler */ "./node_modules/@abaplint/transpiler/build/src/index.js"));
321
320
  const config_1 = __webpack_require__(/*! ./config */ "./build/config.js");
322
321
  const file_operations_1 = __webpack_require__(/*! ./file_operations */ "./build/file_operations.js");
323
322
  const libraries_1 = __webpack_require__(/*! ./libraries */ "./build/libraries.js");
324
323
  const write_objects_1 = __webpack_require__(/*! ./write_objects */ "./build/write_objects.js");
324
+ const output_writer_1 = __webpack_require__(/*! ./output_writer */ "./build/output_writer.js");
325
325
  class Progress {
326
326
  bar;
327
327
  set(total, _text) {
@@ -351,23 +351,23 @@ async function run() {
351
351
  console.log("\nBuilding");
352
352
  const { output, sources } = await build(config, files);
353
353
  console.log("\nOutput");
354
- const outputFolder = config.output_folder;
355
- if (!fs.existsSync(outputFolder)) {
356
- fs.mkdirSync(outputFolder, { recursive: true });
357
- }
358
- await (0, write_objects_1.writeObjects)(output.objects, config, sources);
359
- console.log(output.objects.length + " objects written to disk");
354
+ const artifacts = (0, write_objects_1.collectObjectFiles)(output.objects, config, sources);
360
355
  if (config.write_unit_tests === true) {
361
- // breaking change? rename this output file,
362
- fs.writeFileSync(outputFolder + path.sep + "index.mjs", output.unitTestScript);
363
- fs.writeFileSync(outputFolder + path.sep + "_unit_open.mjs", output.unitTestScriptOpen);
356
+ artifacts.push({ path: "index.mjs", contents: output.unitTestScript });
357
+ artifacts.push({ path: "_unit_open.mjs", contents: output.unitTestScriptOpen });
358
+ }
359
+ artifacts.push({ path: "init.mjs", contents: output.initializationScript });
360
+ artifacts.push({ path: "_init.mjs", contents: output.initializationScript2 });
361
+ artifacts.push({ path: "_top.mjs", contents: `import runtime from "@abaplint/runtime";
362
+ globalThis.abap = new runtime.ABAP();` });
363
+ const written = await (0, output_writer_1.writeOutput)(config.output_folder, artifacts, config.incremental_output === true);
364
+ if (config.incremental_output === true) {
365
+ console.log("Output files: " + written.created + " created, " +
366
+ written.updated + " updated, " + written.unchanged + " unchanged, " + written.deleted + " deleted");
367
+ }
368
+ else {
369
+ console.log(`Output files: ${written.updated} written`);
364
370
  }
365
- // breaking change? rename this output file,
366
- fs.writeFileSync(outputFolder + path.sep + "init.mjs", output.initializationScript);
367
- // new static referenced imports,
368
- fs.writeFileSync(outputFolder + path.sep + "_init.mjs", output.initializationScript2);
369
- fs.writeFileSync(outputFolder + path.sep + "_top.mjs", `import runtime from "@abaplint/runtime";
370
- globalThis.abap = new runtime.ABAP();`);
371
371
  }
372
372
  run().then(() => {
373
373
  process.exit();
@@ -491,6 +491,11 @@ const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_
491
491
  const file_operations_1 = __webpack_require__(/*! ./file_operations */ "./build/file_operations.js");
492
492
  const git_clone_1 = __webpack_require__(/*! ./git_clone */ "./build/git_clone.js");
493
493
  const lib_folder_1 = __webpack_require__(/*! ./lib_folder */ "./build/lib_folder.js");
494
+ function logicalLibrarySource(library, directory, filename) {
495
+ const relative = path.relative(directory, filename).split(path.sep)
496
+ .map(segment => encodeURIComponent(segment)).join("/");
497
+ return "abaplint://" + encodeURIComponent(library) + "/" + relative;
498
+ }
494
499
  function libraryNames(libs) {
495
500
  const used = new Set(["project"]);
496
501
  return libs.map(lib => {
@@ -514,6 +519,7 @@ async function loadLibraries(config) {
514
519
  const names = libraryNames(libs);
515
520
  const result = [];
516
521
  for (const [index, lib] of libs.entries()) {
522
+ const libraryName = names[index];
517
523
  let dir;
518
524
  let cleanupFolder = false;
519
525
  const folder = (0, lib_folder_1.resolveLibFolder)(lib.folder, process.cwd());
@@ -547,8 +553,15 @@ async function loadLibraries(config) {
547
553
  filesToRead.add(filename);
548
554
  }
549
555
  }
550
- const files = await file_operations_1.FileOperations.readAllFiles([...filesToRead], config.output_folder);
551
- result.push({ name: names[index], files });
556
+ const filenames = [...filesToRead];
557
+ const files = await file_operations_1.FileOperations.readAllFiles(filenames, config.output_folder);
558
+ if (cleanupFolder) {
559
+ for (const [index, file] of files.entries()) {
560
+ file.sourceMapPath = logicalLibrarySource(libraryName, dir, filenames[index]);
561
+ delete file.relative;
562
+ }
563
+ }
564
+ result.push({ name: libraryName, files });
552
565
  console.log("\t" + files.length + " files added from lib");
553
566
  }
554
567
  finally {
@@ -604,6 +617,347 @@ function libraryRegistry(files, libraries, skipDuplicateDependencies = false) {
604
617
 
605
618
  /***/ },
606
619
 
620
+ /***/ "./build/output_writer.js"
621
+ /*!********************************!*\
622
+ !*** ./build/output_writer.js ***!
623
+ \********************************/
624
+ (__unused_webpack_module, exports, __webpack_require__) {
625
+
626
+ "use strict";
627
+
628
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
629
+ if (k2 === undefined) k2 = k;
630
+ var desc = Object.getOwnPropertyDescriptor(m, k);
631
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
632
+ desc = { enumerable: true, get: function() { return m[k]; } };
633
+ }
634
+ Object.defineProperty(o, k2, desc);
635
+ }) : (function(o, m, k, k2) {
636
+ if (k2 === undefined) k2 = k;
637
+ o[k2] = m[k];
638
+ }));
639
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
640
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
641
+ }) : function(o, v) {
642
+ o["default"] = v;
643
+ });
644
+ var __importStar = (this && this.__importStar) || (function () {
645
+ var ownKeys = function(o) {
646
+ ownKeys = Object.getOwnPropertyNames || function (o) {
647
+ var ar = [];
648
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
649
+ return ar;
650
+ };
651
+ return ownKeys(o);
652
+ };
653
+ return function (mod) {
654
+ if (mod && mod.__esModule) return mod;
655
+ var result = {};
656
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
657
+ __setModuleDefault(result, mod);
658
+ return result;
659
+ };
660
+ })();
661
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
662
+ exports.writeOutput = writeOutput;
663
+ const fsPromises = __importStar(__webpack_require__(/*! node:fs/promises */ "node:fs/promises"));
664
+ const os = __importStar(__webpack_require__(/*! node:os */ "node:os"));
665
+ const path = __importStar(__webpack_require__(/*! node:path */ "node:path"));
666
+ const file_operations_1 = __webpack_require__(/*! ./file_operations */ "./build/file_operations.js");
667
+ const MANIFEST = ".abap-transpile-manifest.json";
668
+ function concurrency() {
669
+ return Math.max(1, Math.min(8, os.cpus().length));
670
+ }
671
+ async function forEachLimit(items, task, limit = concurrency()) {
672
+ let next = 0;
673
+ const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
674
+ while (next < items.length) {
675
+ const index = next++;
676
+ await task(items[index]);
677
+ }
678
+ });
679
+ const results = await Promise.allSettled(workers);
680
+ const failed = results.find(result => result.status === "rejected");
681
+ if (failed?.status === "rejected") {
682
+ throw failed.reason;
683
+ }
684
+ }
685
+ function normalizeRelative(filename, label) {
686
+ if (filename.length === 0 || filename.startsWith("/") || filename.includes("\\")
687
+ || /^[a-zA-Z]:/.test(filename)) {
688
+ throw new Error("Invalid " + label + " path: " + filename);
689
+ }
690
+ const segments = filename.split("/");
691
+ if (segments.some(segment => segment.length === 0 || segment === "." || segment === "..")) {
692
+ throw new Error("Invalid " + label + " path: " + filename);
693
+ }
694
+ return segments.join("/");
695
+ }
696
+ function validatePaths(filenames, label) {
697
+ const paths = new Map();
698
+ for (const filename of filenames) {
699
+ if (typeof filename !== "string") {
700
+ throw new Error("Invalid " + label + " path");
701
+ }
702
+ const relative = normalizeRelative(filename, label);
703
+ const key = relative.toLowerCase();
704
+ if (key === MANIFEST || key.startsWith(MANIFEST + "/")) {
705
+ throw new Error("Reserved " + label + " path: " + relative);
706
+ }
707
+ const existing = paths.get(key);
708
+ if (existing !== undefined) {
709
+ throw new Error("Conflicting " + label + " paths: " + existing + " and " + relative);
710
+ }
711
+ paths.set(key, relative);
712
+ }
713
+ for (const filename of paths.values()) {
714
+ const segments = filename.split("/");
715
+ for (let index = 1; index < segments.length; index++) {
716
+ if (paths.has(segments.slice(0, index).join("/").toLowerCase())) {
717
+ throw new Error("Conflicting " + label + " file and directory paths: " + filename);
718
+ }
719
+ }
720
+ }
721
+ return [...paths.values()];
722
+ }
723
+ function validateArtifactPaths(artifacts) {
724
+ const paths = validatePaths(artifacts.map(artifact => artifact.path.replace(/\\/g, "/")), "output");
725
+ return artifacts.map((artifact, index) => ({
726
+ ...artifact,
727
+ relative: paths[index],
728
+ byteLength: Buffer.byteLength(artifact.contents, file_operations_1.FileOperations.isBinaryFilename(paths[index]) ? "latin1" : "utf8"),
729
+ binary: file_operations_1.FileOperations.isBinaryFilename(paths[index]),
730
+ }));
731
+ }
732
+ function parseManifest(contents) {
733
+ let parsed;
734
+ try {
735
+ parsed = JSON.parse(contents);
736
+ }
737
+ catch (error) {
738
+ throw new Error("Invalid incremental output manifest JSON: " + String(error));
739
+ }
740
+ if (typeof parsed !== "object" || parsed === null || !("version" in parsed) || !("files" in parsed)
741
+ || parsed.version !== 1 || !Array.isArray(parsed.files)) {
742
+ throw new Error("Unsupported incremental output manifest");
743
+ }
744
+ return { version: 1, files: validatePaths(parsed.files, "incremental output manifest") };
745
+ }
746
+ function serializeManifest(files) {
747
+ return JSON.stringify({ version: 1, files: [...files].sort() }, null, 2) + "\n";
748
+ }
749
+ async function lstatOrMissing(filename) {
750
+ try {
751
+ return await fsPromises.lstat(filename);
752
+ }
753
+ catch (error) {
754
+ if (error.code === "ENOENT") {
755
+ return undefined;
756
+ }
757
+ throw error;
758
+ }
759
+ }
760
+ function isBelowRoot(root, filename) {
761
+ const relative = path.relative(root, filename);
762
+ return relative !== "" && relative !== ".." && !relative.startsWith(".." + path.sep) && !path.isAbsolute(relative);
763
+ }
764
+ async function inspectPaths(root, relativePaths, rootStats, ioConcurrency) {
765
+ const metadata = new Map();
766
+ const nodes = new Map();
767
+ for (const filename of relativePaths) {
768
+ const segments = filename.split("/");
769
+ for (let index = 1; index <= segments.length; index++) {
770
+ const relative = segments.slice(0, index).join("/");
771
+ const isDirectory = index < segments.length;
772
+ nodes.set(relative, (nodes.get(relative) ?? false) || isDirectory);
773
+ }
774
+ }
775
+ if (rootStats !== undefined) {
776
+ const byDepth = new Map();
777
+ for (const relative of nodes.keys()) {
778
+ const depth = relative.split("/").length;
779
+ const group = byDepth.get(depth) ?? [];
780
+ group.push(relative);
781
+ byDepth.set(depth, group);
782
+ }
783
+ for (const depth of [...byDepth.keys()].sort((a, b) => a - b)) {
784
+ const candidates = byDepth.get(depth).filter(relative => {
785
+ const parent = path.posix.dirname(relative);
786
+ return depth === 1 || metadata.get(parent)?.isDirectory() === true;
787
+ });
788
+ await forEachLimit(candidates, async (relative) => {
789
+ const absolute = path.resolve(root, ...relative.split("/"));
790
+ const stat = await lstatOrMissing(absolute);
791
+ if (stat?.isSymbolicLink()) {
792
+ throw new Error("Output path must not traverse a symlink: " + relative);
793
+ }
794
+ if (stat !== undefined && nodes.get(relative) === true && !stat.isDirectory()) {
795
+ throw new Error("Output path parent is not a directory: " + relative);
796
+ }
797
+ if (stat !== undefined && nodes.get(relative) === false && !stat.isFile()) {
798
+ throw new Error("Generated output path is not a regular file: " + relative);
799
+ }
800
+ metadata.set(relative, stat);
801
+ }, ioConcurrency);
802
+ }
803
+ }
804
+ else {
805
+ for (const relative of nodes.keys()) {
806
+ metadata.set(relative, undefined);
807
+ }
808
+ }
809
+ return metadata;
810
+ }
811
+ async function atomicWriteManifest(root, contents, current) {
812
+ if (current === contents) {
813
+ return;
814
+ }
815
+ await fsPromises.mkdir(root, { recursive: true });
816
+ const temporary = path.join(root, MANIFEST + ".tmp-" + process.pid + "-" + Math.random().toString(36).slice(2));
817
+ try {
818
+ await fsPromises.writeFile(temporary, contents, { flag: "wx", encoding: "utf8" });
819
+ await fsPromises.rename(temporary, path.join(root, MANIFEST));
820
+ }
821
+ catch (error) {
822
+ try {
823
+ await fsPromises.unlink(temporary);
824
+ }
825
+ catch {
826
+ // The temporary file can be absent when creation failed.
827
+ }
828
+ throw error;
829
+ }
830
+ }
831
+ async function writeOutput(rootFolder, artifacts, incremental, ioConcurrency = concurrency()) {
832
+ const root = path.resolve(rootFolder);
833
+ const prepared = validateArtifactPaths(artifacts);
834
+ const result = {
835
+ created: 0, updated: 0, unchanged: 0, deleted: 0,
836
+ };
837
+ if (!incremental) {
838
+ const files = prepared.map(file => ({ path: path.resolve(root, file.relative), contents: file.contents }));
839
+ await file_operations_1.FileOperations.writeFiles(files);
840
+ result.updated = files.length;
841
+ return result;
842
+ }
843
+ const manifestPath = path.join(root, MANIFEST);
844
+ const rootStats = await lstatOrMissing(root);
845
+ if (rootStats?.isSymbolicLink()) {
846
+ throw new Error("Output folder must not be a symlink: " + root);
847
+ }
848
+ if (rootStats !== undefined && !rootStats.isDirectory()) {
849
+ throw new Error("Output folder is not a directory: " + root);
850
+ }
851
+ let manifestContents;
852
+ let previous = [];
853
+ if (rootStats !== undefined) {
854
+ const manifestStat = await lstatOrMissing(manifestPath);
855
+ if (manifestStat?.isSymbolicLink() || (manifestStat !== undefined && !manifestStat.isFile())) {
856
+ throw new Error("Incremental output manifest must be a regular file");
857
+ }
858
+ if (manifestStat !== undefined) {
859
+ const contents = await fsPromises.readFile(manifestPath, "utf8");
860
+ manifestContents = contents;
861
+ previous = parseManifest(contents).files;
862
+ }
863
+ }
864
+ // A path can belong to both inventories; each inventory rejects its own duplicates.
865
+ validatePaths([...new Set([...prepared.map(file => file.relative), ...previous])], "incremental output");
866
+ const previousPaths = new Set(previous);
867
+ const current = new Set(prepared.map(file => file.relative));
868
+ const stale = previous.filter(filename => !current.has(filename));
869
+ const additions = prepared.some(file => !previousPaths.has(file.relative));
870
+ const pathsToInspect = [...new Set([...prepared.map(file => file.relative), ...stale])];
871
+ const metadata = await inspectPaths(root, pathsToInspect, rootStats, ioConcurrency);
872
+ await forEachLimit(prepared, async (file) => {
873
+ const stat = metadata.get(file.relative);
874
+ file.existed = stat !== undefined;
875
+ if (stat === undefined || stat.size !== file.byteLength) {
876
+ file.changed = true;
877
+ return;
878
+ }
879
+ let existing;
880
+ try {
881
+ existing = await fsPromises.readFile(path.resolve(root, ...file.relative.split("/")));
882
+ }
883
+ catch (error) {
884
+ if (error.code === "ENOENT") {
885
+ file.existed = false;
886
+ file.changed = true;
887
+ return;
888
+ }
889
+ throw error;
890
+ }
891
+ const generated = Buffer.from(file.contents, file.binary ? "latin1" : "utf8");
892
+ file.changed = !existing.equals(generated);
893
+ }, ioConcurrency);
894
+ if (additions) {
895
+ const union = serializeManifest(new Set([...previous, ...current]));
896
+ await atomicWriteManifest(root, union, manifestContents);
897
+ manifestContents = union;
898
+ }
899
+ const toWrite = prepared.filter(file => file.changed);
900
+ const directories = new Map();
901
+ for (const file of toWrite) {
902
+ const segments = file.relative.split("/");
903
+ for (let index = 1; index < segments.length; index++) {
904
+ const relative = segments.slice(0, index).join("/");
905
+ if (metadata.get(relative) === undefined) {
906
+ directories.set(relative, index);
907
+ }
908
+ }
909
+ }
910
+ const directoryDepths = [...new Set(directories.values())].sort((a, b) => a - b);
911
+ for (const depth of directoryDepths) {
912
+ const atDepth = [...directories.entries()].filter(([, candidateDepth]) => candidateDepth === depth)
913
+ .map(([relative]) => path.resolve(root, ...relative.split("/")));
914
+ await forEachLimit(atDepth, async (directory) => {
915
+ await fsPromises.mkdir(directory);
916
+ }, ioConcurrency);
917
+ }
918
+ await forEachLimit(toWrite, async (file) => {
919
+ await fsPromises.writeFile(path.resolve(root, ...file.relative.split("/")), file.contents, file.binary ? { encoding: "latin1" } : undefined);
920
+ }, ioConcurrency);
921
+ const staleFiles = stale.map(filename => path.resolve(root, ...filename.split("/")));
922
+ const removedDirectories = new Set();
923
+ for (const filename of staleFiles) {
924
+ try {
925
+ await fsPromises.unlink(filename);
926
+ result.deleted++;
927
+ }
928
+ catch (error) {
929
+ if (error.code !== "ENOENT") {
930
+ throw error;
931
+ }
932
+ }
933
+ let directory = path.dirname(filename);
934
+ while (isBelowRoot(root, directory)) {
935
+ removedDirectories.add(directory);
936
+ directory = path.dirname(directory);
937
+ }
938
+ }
939
+ await forEachLimit([...removedDirectories].sort((a, b) => b.length - a.length), async (directory) => {
940
+ try {
941
+ await fsPromises.rmdir(directory);
942
+ }
943
+ catch (error) {
944
+ const code = error.code;
945
+ if (code !== "ENOENT" && code !== "ENOTEMPTY" && code !== "EEXIST") {
946
+ throw error;
947
+ }
948
+ }
949
+ });
950
+ const finalManifest = serializeManifest(current);
951
+ await atomicWriteManifest(root, finalManifest, manifestContents);
952
+ result.created = prepared.filter(file => file.changed && !file.existed).length;
953
+ result.updated = prepared.filter(file => file.changed && file.existed).length;
954
+ result.unchanged = prepared.filter(file => !file.changed).length;
955
+ return result;
956
+ }
957
+ //# sourceMappingURL=output_writer.js.map
958
+
959
+ /***/ },
960
+
607
961
  /***/ "./build/write_objects.js"
608
962
  /*!********************************!*\
609
963
  !*** ./build/write_objects.js ***!
@@ -646,28 +1000,16 @@ var __importStar = (this && this.__importStar) || (function () {
646
1000
  };
647
1001
  })();
648
1002
  Object.defineProperty(exports, "__esModule", ({ value: true }));
649
- exports.writeObjects = writeObjects;
1003
+ exports.collectObjectFiles = collectObjectFiles;
650
1004
  const path = __importStar(__webpack_require__(/*! path */ "path"));
651
1005
  const url_1 = __webpack_require__(/*! url */ "url");
652
1006
  const transpiler_1 = __webpack_require__(/*! @abaplint/transpiler */ "./node_modules/@abaplint/transpiler/build/src/index.js");
653
- const file_operations_1 = __webpack_require__(/*! ./file_operations */ "./build/file_operations.js");
654
- async function writeObjects(outputFiles, config, files) {
1007
+ function collectObjectFiles(outputFiles, config, files) {
655
1008
  const root = path.resolve(config.output_folder);
656
1009
  const filesToWrite = [];
657
- const destinations = new Set();
658
1010
  const sources = new Map(files.map(file => [file.filename.toLowerCase(), file]));
659
1011
  const add = (filename, contents) => {
660
- const target = path.resolve(root, filename);
661
- const relative = path.relative(root, target);
662
- if (relative === "" || relative.startsWith(".." + path.sep) || relative === ".." || path.isAbsolute(relative)) {
663
- throw new Error("Output file escapes output_folder: " + filename);
664
- }
665
- const key = target.toLowerCase();
666
- if (destinations.has(key)) {
667
- throw new Error("Conflicting output file: " + filename);
668
- }
669
- destinations.add(key);
670
- filesToWrite.push({ path: target, contents });
1012
+ filesToWrite.push({ path: filename.replace(/\\/g, "/"), contents });
671
1013
  };
672
1014
  for (const output of outputFiles) {
673
1015
  const type = output.object.type.toUpperCase();
@@ -688,21 +1030,24 @@ async function writeObjects(outputFiles, config, files) {
688
1030
  if (file === undefined) {
689
1031
  continue;
690
1032
  }
691
- if (file.relative !== undefined) {
1033
+ if (file.sourceMapPath !== undefined) {
1034
+ sourcePaths[filename] = file.sourceMapPath;
1035
+ }
1036
+ else if (file.relative !== undefined) {
692
1037
  const source = path.resolve(root, file.relative, file.filename);
693
1038
  const relative = path.relative(mapDirectory, source);
694
1039
  // Sources on another Windows drive cannot be expressed as relative paths.
695
1040
  sourcePaths[filename] = path.isAbsolute(relative) ? (0, url_1.pathToFileURL)(source).href
696
1041
  : relative.split(path.sep).map(segment => encodeURIComponent(segment)).join("/");
697
1042
  }
698
- // Include sources for local and cloned libraries; clones are removed before emission.
1043
+ // Embedding source text keeps maps useful after temporary checkouts are removed.
699
1044
  sourceContents[filename] = file.contents;
700
1045
  }
701
1046
  add(name, output.chunk.getMap(path.basename(output.filename), { generatedLineOffset, sourcePaths, sourceContents }));
702
1047
  }
703
1048
  add(output.filename, contents);
704
1049
  }
705
- await file_operations_1.FileOperations.writeFiles(filesToWrite);
1050
+ return filesToWrite;
706
1051
  }
707
1052
  //# sourceMappingURL=write_objects.js.map
708
1053
 
@@ -1060,7 +1405,7 @@ class Lexer {
1060
1405
  else if (this.m === ModeTemplate
1061
1406
  && this.buffer.length() > 1
1062
1407
  && (current === CH_PIPE || current === CH_LBRACE)
1063
- && (stream.prevChar() !== CH_BACKSLASH || (stream.prevPrevChar() === CH_BACKSLASH && stream.prevChar() === CH_BACKSLASH))) {
1408
+ && stream.countPrevious(CH_BACKSLASH) % 2 === 0) {
1064
1409
  // end of template
1065
1410
  if (current === CH_LBRACE || AFTER_LITERAL.has(ahead)) {
1066
1411
  this.add();
@@ -1214,6 +1559,14 @@ class LexerStream {
1214
1559
  }
1215
1560
  return this.raw.charCodeAt(o);
1216
1561
  }
1562
+ /** number of consecutive occurrences of the character directly before the current one */
1563
+ countPrevious(code) {
1564
+ let count = 0;
1565
+ for (let o = this.offset - 1; o >= 0 && this.raw.charCodeAt(o) === code; o--) {
1566
+ count++;
1567
+ }
1568
+ return count;
1569
+ }
1217
1570
  currentChar() {
1218
1571
  if (this.offset < 0) {
1219
1572
  return NL; // simulate newline at start of file to handle star(*) comments
@@ -21213,6 +21566,21 @@ exports.sta = sta;
21213
21566
  exports.sub = sub;
21214
21567
  const nodes_1 = __webpack_require__(/*! ../../nodes */ "./node_modules/@abaplint/core/build/src/abap/nodes/index.js");
21215
21568
  const _statement_1 = __webpack_require__(/*! ../../2_statements/statements/_statement */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/_statement.js");
21569
+ function toMatch(statements, m) {
21570
+ return {
21571
+ matched: statements.slice(0, m.next),
21572
+ unmatched: statements.slice(m.next),
21573
+ error: m.error,
21574
+ errorDescription: m.errorDescription,
21575
+ errorMatched: m.errorMatched,
21576
+ };
21577
+ }
21578
+ function success(next) {
21579
+ return { next, error: false, errorDescription: "", errorMatched: 0 };
21580
+ }
21581
+ function failure(next, errorDescription, errorMatched) {
21582
+ return { next, error: true, errorDescription, errorMatched };
21583
+ }
21216
21584
  class Sequence {
21217
21585
  constructor(list) {
21218
21586
  if (list.length < 2) {
@@ -21231,36 +21599,18 @@ class Sequence {
21231
21599
  return this.list[0].first();
21232
21600
  }
21233
21601
  run(statements, parent) {
21234
- let inn = statements;
21235
- let out = [];
21602
+ return toMatch(statements, this.runAt(statements, 0, parent));
21603
+ }
21604
+ runAt(statements, index, parent) {
21605
+ let next = index;
21236
21606
  for (const i of this.list) {
21237
- const match = i.run(inn, parent);
21607
+ const match = i.runAt(statements, next, parent);
21238
21608
  if (match.error) {
21239
- return {
21240
- matched: [],
21241
- unmatched: statements,
21242
- error: true,
21243
- errorDescription: match.errorDescription,
21244
- errorMatched: out.length,
21245
- };
21246
- }
21247
- if (match.matched.length < 100) {
21248
- out.push(...match.matched);
21249
- }
21250
- else {
21251
- // avoid using the spread operator, it might trigger "Maximum call stack size exceeded"
21252
- // when the number of matched elements is very large
21253
- out = out.concat(match.matched);
21609
+ return failure(index, match.errorDescription, next - index);
21254
21610
  }
21255
- inn = match.unmatched;
21611
+ next = match.next;
21256
21612
  }
21257
- return {
21258
- matched: out,
21259
- unmatched: inn,
21260
- error: false,
21261
- errorDescription: "",
21262
- errorMatched: 0,
21263
- };
21613
+ return success(next);
21264
21614
  }
21265
21615
  }
21266
21616
  // Note that the Alternative does not nessesarily return the first in the alternative
@@ -21299,21 +21649,18 @@ class Alternative {
21299
21649
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
21300
21650
  }
21301
21651
  run(statements, parent) {
21652
+ return toMatch(statements, this.runAt(statements, 0, parent));
21653
+ }
21654
+ runAt(statements, index, parent) {
21302
21655
  this.setupMap();
21303
21656
  let count = 0;
21304
21657
  let countError = "";
21305
- if (statements.length === 0) {
21306
- return {
21307
- matched: [],
21308
- unmatched: statements,
21309
- error: true,
21310
- errorDescription: countError,
21311
- errorMatched: count,
21312
- };
21658
+ if (index >= statements.length) {
21659
+ return failure(index, countError, count);
21313
21660
  }
21314
- const token = statements[0].getFirstToken().getStr().toUpperCase();
21661
+ const token = statements[index].getFirstToken().getStr().toUpperCase();
21315
21662
  for (const i of this.map[token] || []) {
21316
- const match = i.run(statements, parent);
21663
+ const match = i.runAt(statements, index, parent);
21317
21664
  if (match.error === false) {
21318
21665
  return match;
21319
21666
  }
@@ -21323,7 +21670,7 @@ class Alternative {
21323
21670
  }
21324
21671
  }
21325
21672
  for (const i of this.map[""] || []) {
21326
- const match = i.run(statements, parent);
21673
+ const match = i.runAt(statements, index, parent);
21327
21674
  if (match.error === false) {
21328
21675
  return match;
21329
21676
  }
@@ -21333,22 +21680,10 @@ class Alternative {
21333
21680
  }
21334
21681
  }
21335
21682
  if (count === 0) {
21336
- return {
21337
- matched: [],
21338
- unmatched: statements,
21339
- error: true,
21340
- errorDescription: "Unexpected code structure",
21341
- errorMatched: count,
21342
- };
21683
+ return failure(index, "Unexpected code structure", count);
21343
21684
  }
21344
21685
  else {
21345
- return {
21346
- matched: [],
21347
- unmatched: statements,
21348
- error: true,
21349
- errorDescription: countError,
21350
- errorMatched: count,
21351
- };
21686
+ return failure(index, countError, count);
21352
21687
  }
21353
21688
  }
21354
21689
  }
@@ -21363,7 +21698,10 @@ class Optional {
21363
21698
  return this.obj.getUsing();
21364
21699
  }
21365
21700
  run(statements, parent) {
21366
- const ret = this.obj.run(statements, parent);
21701
+ return toMatch(statements, this.runAt(statements, 0, parent));
21702
+ }
21703
+ runAt(statements, index, parent) {
21704
+ const ret = this.obj.runAt(statements, index, parent);
21367
21705
  ret.error = false;
21368
21706
  return ret;
21369
21707
  }
@@ -21382,48 +21720,24 @@ class Star {
21382
21720
  return this.obj.getUsing();
21383
21721
  }
21384
21722
  run(statements, parent) {
21385
- let inn = statements;
21386
- let out = [];
21723
+ return toMatch(statements, this.runAt(statements, 0, parent));
21724
+ }
21725
+ runAt(statements, index, parent) {
21726
+ let next = index;
21387
21727
  while (true) {
21388
- if (inn.length === 0) {
21389
- return {
21390
- matched: out,
21391
- unmatched: inn,
21392
- error: false,
21393
- errorDescription: "",
21394
- errorMatched: 0,
21395
- };
21728
+ if (next >= statements.length) {
21729
+ return success(next);
21396
21730
  }
21397
- const match = this.obj.run(inn, parent);
21731
+ const match = this.obj.runAt(statements, next, parent);
21398
21732
  if (match.error === true) {
21399
21733
  if (match.errorMatched > 0) {
21400
- return {
21401
- matched: out,
21402
- unmatched: inn,
21403
- error: true,
21404
- errorDescription: match.errorDescription,
21405
- errorMatched: match.errorMatched,
21406
- };
21734
+ return failure(next, match.errorDescription, match.errorMatched);
21407
21735
  }
21408
21736
  else {
21409
- return {
21410
- matched: out,
21411
- unmatched: inn,
21412
- error: false,
21413
- errorDescription: "",
21414
- errorMatched: 0,
21415
- };
21737
+ return success(next);
21416
21738
  }
21417
21739
  }
21418
- if (match.matched.length < 100) {
21419
- out.push(...match.matched);
21420
- }
21421
- else {
21422
- // avoid using the spread operator, it might trigger "Maximum call stack size exceeded"
21423
- // when the number of matched elements is very large
21424
- out = out.concat(match.matched);
21425
- }
21426
- inn = match.unmatched;
21740
+ next = match.next;
21427
21741
  }
21428
21742
  }
21429
21743
  first() {
@@ -21452,10 +21766,13 @@ class SubStructure {
21452
21766
  }
21453
21767
  }
21454
21768
  run(statements, parent) {
21769
+ return toMatch(statements, this.runAt(statements, 0, parent));
21770
+ }
21771
+ runAt(statements, index, parent) {
21455
21772
  const nparent = new nodes_1.StructureNode(this.s);
21456
21773
  this.setupMatcher();
21457
- const ret = this.matcher.run(statements, nparent);
21458
- if (ret.matched.length === 0) {
21774
+ const ret = this.matcher.runAt(statements, index, nparent);
21775
+ if (ret.next === index) {
21459
21776
  ret.error = true;
21460
21777
  }
21461
21778
  else {
@@ -21485,33 +21802,18 @@ class SubStatement {
21485
21802
  return this.obj.name;
21486
21803
  }
21487
21804
  run(statements, parent) {
21488
- if (statements.length === 0) {
21489
- return {
21490
- matched: [],
21491
- unmatched: [],
21492
- error: true,
21493
- errorDescription: "Expected " + this.className().toUpperCase(),
21494
- errorMatched: 0,
21495
- };
21805
+ return toMatch(statements, this.runAt(statements, 0, parent));
21806
+ }
21807
+ runAt(statements, index, parent) {
21808
+ if (index >= statements.length) {
21809
+ return failure(statements.length, "Expected " + this.className().toUpperCase(), 0);
21496
21810
  }
21497
- else if (statements[0].get() instanceof this.obj) {
21498
- parent.addChild(statements[0]);
21499
- return {
21500
- matched: [statements[0]],
21501
- unmatched: statements.splice(1),
21502
- error: false,
21503
- errorDescription: "",
21504
- errorMatched: 0,
21505
- };
21811
+ else if (statements[index].get() instanceof this.obj) {
21812
+ parent.addChild(statements[index]);
21813
+ return success(index + 1);
21506
21814
  }
21507
21815
  else {
21508
- return {
21509
- matched: [],
21510
- unmatched: statements,
21511
- error: true,
21512
- errorDescription: "Expected " + this.className().toUpperCase(),
21513
- errorMatched: 0,
21514
- };
21816
+ return failure(index, "Expected " + this.className().toUpperCase(), 0);
21515
21817
  }
21516
21818
  }
21517
21819
  }
@@ -29257,7 +29559,7 @@ class BasicTypes {
29257
29559
  if (children.length === 0) {
29258
29560
  return new Types.UnknownType("Type error, could not resolve \"" + fullName + "\", resolveLikeName1");
29259
29561
  }
29260
- let type = undefined;
29562
+ let type;
29261
29563
  if (children[1] && (children[1].getFirstToken().getStr() === "=>" || children[1].getFirstToken().getStr() === "->")) {
29262
29564
  type = field_chain_1.FieldChain.runSyntax(chain, this.input, _reference_1.ReferenceType.TypeReference);
29263
29565
  }
@@ -29520,7 +29822,7 @@ class BasicTypes {
29520
29822
  primaryKey: primaryKey,
29521
29823
  secondary: secondaryKeys,
29522
29824
  };
29523
- let found = undefined;
29825
+ let found;
29524
29826
  if (text.startsWith("TYPE TABLE OF REF TO ")
29525
29827
  || text.startsWith("TYPE STANDARD TABLE OF REF TO ")
29526
29828
  || text.startsWith("TYPE SORTED TABLE OF REF TO ")
@@ -29658,7 +29960,7 @@ class BasicTypes {
29658
29960
  name = typeName === null || typeName === void 0 ? void 0 : typeName.concatTokens();
29659
29961
  }
29660
29962
  const type = this.resolveLikeName(e, false);
29661
- let row = undefined;
29963
+ let row;
29662
29964
  if (type === undefined) {
29663
29965
  return new Types.UnknownType("Type error, could not resolve \"" + name + "\", parseType");
29664
29966
  }
@@ -29853,7 +30155,7 @@ class BasicTypes {
29853
30155
  rest = split[1];
29854
30156
  }
29855
30157
  const subs = rest.split("-");
29856
- let foundType = undefined;
30158
+ let foundType;
29857
30159
  if (className && chainText.includes("=>")) {
29858
30160
  const split = chainText.split("=>");
29859
30161
  const className = split[0];
@@ -30276,6 +30578,143 @@ function checkDatabaseFields(fields, dbSources, input, token) {
30276
30578
 
30277
30579
  /***/ },
30278
30580
 
30581
+ /***/ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_work_area.js"
30582
+ /*!******************************************************************************************************!*\
30583
+ !*** ./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_work_area.js ***!
30584
+ \******************************************************************************************************/
30585
+ (__unused_webpack_module, exports, __webpack_require__) {
30586
+
30587
+ "use strict";
30588
+
30589
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
30590
+ if (k2 === undefined) k2 = k;
30591
+ var desc = Object.getOwnPropertyDescriptor(m, k);
30592
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
30593
+ desc = { enumerable: true, get: function() { return m[k]; } };
30594
+ }
30595
+ Object.defineProperty(o, k2, desc);
30596
+ }) : (function(o, m, k, k2) {
30597
+ if (k2 === undefined) k2 = k;
30598
+ o[k2] = m[k];
30599
+ }));
30600
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30601
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30602
+ }) : function(o, v) {
30603
+ o["default"] = v;
30604
+ });
30605
+ var __importStar = (this && this.__importStar) || (function () {
30606
+ var ownKeys = function(o) {
30607
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30608
+ var ar = [];
30609
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30610
+ return ar;
30611
+ };
30612
+ return ownKeys(o);
30613
+ };
30614
+ return function (mod) {
30615
+ if (mod && mod.__esModule) return mod;
30616
+ var result = {};
30617
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
30618
+ __setModuleDefault(result, mod);
30619
+ return result;
30620
+ };
30621
+ })();
30622
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
30623
+ exports.checkDatabaseWorkArea = checkDatabaseWorkArea;
30624
+ const nodes_1 = __webpack_require__(/*! ../../nodes */ "./node_modules/@abaplint/core/build/src/abap/nodes/index.js");
30625
+ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
30626
+ const Basic = __importStar(__webpack_require__(/*! ../../types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js"));
30627
+ const objects_1 = __webpack_require__(/*! ../../../objects */ "./node_modules/@abaplint/core/build/src/objects/index.js");
30628
+ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
30629
+ // byte length of a flat type in a unicode system, as a lower and an upper bound:
30630
+ // IntegerType also stands for INT1 and INT2, and padding is left out of the lower bound
30631
+ function bounds(type) {
30632
+ if (type instanceof Basic.CharacterType || type instanceof Basic.NumericType) {
30633
+ return { min: type.getLength() * 2, max: type.getLength() * 2, align: 2 };
30634
+ }
30635
+ else if (type instanceof Basic.DateType) {
30636
+ return { min: 16, max: 16, align: 2 };
30637
+ }
30638
+ else if (type instanceof Basic.TimeType) {
30639
+ return { min: 12, max: 12, align: 2 };
30640
+ }
30641
+ else if (type instanceof Basic.IntegerType) {
30642
+ return { min: 1, max: 4, align: 4 };
30643
+ }
30644
+ else if (type instanceof Basic.Integer8Type || type instanceof Basic.FloatType
30645
+ || type instanceof Basic.DecFloat16Type || type instanceof Basic.UTCLongType) {
30646
+ return { min: 8, max: 8, align: 8 };
30647
+ }
30648
+ else if (type instanceof Basic.DecFloat34Type) {
30649
+ return { min: 16, max: 16, align: 16 };
30650
+ }
30651
+ else if (type instanceof Basic.PackedType || type instanceof Basic.HexType) {
30652
+ return { min: type.getLength(), max: type.getLength(), align: 1 };
30653
+ }
30654
+ else if (type instanceof Basic.StructureType) {
30655
+ let min = 0;
30656
+ let max = 0;
30657
+ let align = 1;
30658
+ for (const component of type.getComponents()) {
30659
+ const sub = bounds(component.type);
30660
+ if (sub === undefined) {
30661
+ return undefined;
30662
+ }
30663
+ align = Math.max(align, sub.align);
30664
+ max = Math.ceil(max / sub.align) * sub.align + sub.max;
30665
+ min = min + sub.min;
30666
+ }
30667
+ max = Math.ceil(max / align) * align;
30668
+ return { min, max, align };
30669
+ }
30670
+ // deep, generic, void or unknown
30671
+ return undefined;
30672
+ }
30673
+ // INSERT/MODIFY/UPDATE dbtab FROM wa: the work area must be at least as long as the table line,
30674
+ // client field included, else the statement is a syntax error on the system
30675
+ function checkDatabaseWorkArea(node, dbSource, sourceTypes, input) {
30676
+ var _a;
30677
+ if (!(dbSource instanceof objects_1.Table)) {
30678
+ return;
30679
+ }
30680
+ const children = node.getChildren();
30681
+ let workArea = undefined;
30682
+ for (let i = 0; i < children.length - 1; i++) {
30683
+ const child = children[i];
30684
+ if (child instanceof nodes_1.TokenNode && child.concatTokens().toUpperCase() === "FROM") {
30685
+ const next = children[i + 1];
30686
+ if (next instanceof nodes_1.ExpressionNode && next.get() instanceof Expressions.SQLSource) {
30687
+ workArea = next;
30688
+ }
30689
+ break;
30690
+ }
30691
+ }
30692
+ if (workArea === undefined) {
30693
+ return;
30694
+ }
30695
+ const source = (_a = workArea.findFirstExpression(Expressions.SimpleSource3)) !== null && _a !== void 0 ? _a : workArea.findFirstExpression(Expressions.Source);
30696
+ if (source === undefined) {
30697
+ return;
30698
+ }
30699
+ const waType = sourceTypes.get(source);
30700
+ if (!(waType instanceof Basic.StructureType)) {
30701
+ return;
30702
+ }
30703
+ const tableType = dbSource.parseType(input.scope.getRegistry());
30704
+ const waBounds = bounds(waType);
30705
+ const tableBounds = bounds(tableType);
30706
+ if (waBounds === undefined || tableBounds === undefined) {
30707
+ return;
30708
+ }
30709
+ if (waBounds.max < tableBounds.min) {
30710
+ const message = "The work area \"" + source.concatTokens() + "\" is not long enough for table " + dbSource.getName();
30711
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, source.getFirstToken(), message));
30712
+ }
30713
+ }
30714
+ //# sourceMappingURL=_check_database_work_area.js.map
30715
+
30716
+ /***/ },
30717
+
30279
30718
  /***/ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js"
30280
30719
  /*!*************************************************************************************************!*\
30281
30720
  !*** ./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js ***!
@@ -30597,7 +31036,7 @@ class AttributeName {
30597
31036
  return context;
30598
31037
  }
30599
31038
  const helper = new _object_oriented_1.ObjectOriented(input.scope);
30600
- let ret = undefined;
31039
+ let ret;
30601
31040
  if (context instanceof object_reference_type_1.ObjectReferenceType) {
30602
31041
  const def = input.scope.findObjectDefinition(context.getIdentifierName());
30603
31042
  if (def === undefined) {
@@ -31622,7 +32061,7 @@ const let_1 = __webpack_require__(/*! ./let */ "./node_modules/@abaplint/core/bu
31622
32061
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
31623
32062
  const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
31624
32063
  class ConvBody {
31625
- static runSyntax(node, input) {
32064
+ static runSyntax(node, input, targetType) {
31626
32065
  let scoped = false;
31627
32066
  const l = node.findDirectExpression(Expressions.Let);
31628
32067
  if (l) {
@@ -31634,7 +32073,7 @@ class ConvBody {
31634
32073
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
31635
32074
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
31636
32075
  }
31637
- const sourceType = source_1.Source.runSyntax(s, input);
32076
+ const sourceType = source_1.Source.runSyntax(s, input, targetType);
31638
32077
  if (scoped === true) {
31639
32078
  input.scope.pop(node.getLastToken().getEnd());
31640
32079
  }
@@ -32167,7 +32606,7 @@ class FieldChain {
32167
32606
  return found.getType();
32168
32607
  }
32169
32608
  }
32170
- let context = undefined;
32609
+ let context;
32171
32610
  const children = node.getChildren();
32172
32611
  context = this.findTop(children[0], input, refType);
32173
32612
  let prev = children[0].concatTokens();
@@ -32660,7 +33099,7 @@ class FormParam {
32660
33099
  if (node.findDirectTokenByText("STRUCTURE") && nameToken) {
32661
33100
  // STRUCTURES typing
32662
33101
  const typeName = (_a = node.findDirectExpression(expressions_1.SimpleFieldChain)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr();
32663
- let type = undefined;
33102
+ let type;
32664
33103
  if (typeName) {
32665
33104
  type = (_b = input.scope.findType(typeName)) === null || _b === void 0 ? void 0 : _b.getType();
32666
33105
  if (type === undefined) {
@@ -34233,7 +34672,7 @@ class MethodParameters {
34233
34672
  }
34234
34673
  checkImporting(node, input, method) {
34235
34674
  for (const item of this.parameterListT(node, input)) {
34236
- let parameterType = undefined;
34675
+ let parameterType;
34237
34676
  if (method instanceof basic_1.VoidType) {
34238
34677
  parameterType = method;
34239
34678
  }
@@ -34270,7 +34709,7 @@ class MethodParameters {
34270
34709
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
34271
34710
  return;
34272
34711
  }
34273
- let parameterType = undefined;
34712
+ let parameterType;
34274
34713
  if (method instanceof basic_1.VoidType) {
34275
34714
  parameterType = method;
34276
34715
  }
@@ -35587,9 +36026,8 @@ class Select {
35587
36026
  }
35588
36027
  static findFields(node, input) {
35589
36028
  var _a, _b;
35590
- let expr = undefined;
36029
+ const expr = node.findFirstExpression(Expressions.SQLFieldList);
35591
36030
  const ret = [];
35592
- expr = node.findFirstExpression(Expressions.SQLFieldList);
35593
36031
  if (((_a = expr === null || expr === void 0 ? void 0 : expr.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.Dynamic) {
35594
36032
  dynamic_1.Dynamic.runSyntax(expr.getFirstChild(), input);
35595
36033
  }
@@ -35683,6 +36121,7 @@ const _typed_identifier_1 = __webpack_require__(/*! ../../types/_typed_identifie
35683
36121
  const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_type_utils.js");
35684
36122
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
35685
36123
  const assert_error_1 = __webpack_require__(/*! ../assert_error */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/assert_error.js");
36124
+ const version_1 = __webpack_require__(/*! ../../../version */ "./node_modules/@abaplint/core/build/src/version.js");
35686
36125
  /*
35687
36126
  * Type interference, valid scenarios:
35688
36127
  * typed = VALUE #( ... ). right hand side must follow left hand type
@@ -35695,7 +36134,7 @@ const assert_error_1 = __webpack_require__(/*! ../assert_error */ "./node_module
35695
36134
  // TODO: refactor all these method parameters to objects, this is getting messy
35696
36135
  class Source {
35697
36136
  static runSyntax(node, input, targetType, writeReference = false, allowGenericDeference = false, readReference = true) {
35698
- var _a;
36137
+ var _a, _b, _c, _d;
35699
36138
  if (node === undefined) {
35700
36139
  return undefined;
35701
36140
  }
@@ -35773,7 +36212,7 @@ class Source {
35773
36212
  case "CONV":
35774
36213
  {
35775
36214
  const foundType = this.determineType(node, input, targetType);
35776
- const bodyType = conv_body_1.ConvBody.runSyntax(node.findDirectExpression(Expressions.ConvBody), input);
36215
+ const bodyType = conv_body_1.ConvBody.runSyntax(node.findDirectExpression(Expressions.ConvBody), input, foundType);
35777
36216
  const inferred = (_a = node.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _a === void 0 ? void 0 : _a.concatTokens();
35778
36217
  if (new _type_utils_1.TypeUtils(input.scope).isConvable(foundType, bodyType) === false) {
35779
36218
  const message = `CONV: Types not compatible, ${foundType === null || foundType === void 0 ? void 0 : foundType.constructor.name}, ${bodyType === null || bodyType === void 0 ? void 0 : bodyType.constructor.name}`;
@@ -35790,7 +36229,13 @@ class Source {
35790
36229
  this.traverseRemainingChildren(children, input);
35791
36230
  return bodyType;
35792
36231
  }
35793
- this.addIfInferred(node, input, foundType);
36232
+ const bodySource = (_b = node.findDirectExpression(Expressions.ConvBody)) === null || _b === void 0 ? void 0 : _b.findDirectExpression(Expressions.Source);
36233
+ const nestedType = (_c = bodySource === null || bodySource === void 0 ? void 0 : bodySource.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _c === void 0 ? void 0 : _c.concatTokens();
36234
+ // CONV # passes its target type into a nested inferred constructor, so
36235
+ // showing both inferred types would produce duplicate inlay hints.
36236
+ if (!(inferred === "#" && nestedType === "#")) {
36237
+ this.addIfInferred(node, input, foundType);
36238
+ }
35794
36239
  this.traverseRemainingChildren(children, input);
35795
36240
  return foundType;
35796
36241
  }
@@ -35847,6 +36292,15 @@ class Source {
35847
36292
  case "CORRESPONDING":
35848
36293
  {
35849
36294
  const foundType = this.determineType(node, input, targetType);
36295
+ if ((foundType === null || foundType === void 0 ? void 0 : foundType.isGeneric()) === true
36296
+ && ((_d = node.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _d === void 0 ? void 0 : _d.concatTokens()) === "#"
36297
+ && !(0, version_1.releaseAtLeast)(input.scope.getRelease(), version_1.Release.v756)
36298
+ && input.scope.getLanguageVersion() !== version_1.LanguageVersion.Cloud
36299
+ && !input.scope.getOpenABAP()) {
36300
+ const message = "CORRESPONDING #, the type of the target is generic";
36301
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
36302
+ return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
36303
+ }
35850
36304
  corresponding_body_1.CorrespondingBody.runSyntax(node.findDirectExpression(Expressions.CorrespondingBody), input, foundType);
35851
36305
  this.addIfInferred(node, input, foundType);
35852
36306
  return foundType;
@@ -38492,6 +38946,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@ab
38492
38946
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/dynamic.js");
38493
38947
  const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_type_utils.js");
38494
38948
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
38949
+ const version_1 = __webpack_require__(/*! ../../../version */ "./node_modules/@abaplint/core/build/src/version.js");
38495
38950
  class Assign {
38496
38951
  runSyntax(node, input) {
38497
38952
  var _a;
@@ -38499,7 +38954,7 @@ class Assign {
38499
38954
  const isComponent = ((_a = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getFirstChild()) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase()) === "COMPONENT";
38500
38955
  const sources = (assignSource === null || assignSource === void 0 ? void 0 : assignSource.findDirectExpressionsMulti([Expressions.Source, Expressions.SimpleSource3])) || [];
38501
38956
  const theSource = sources[sources.length - 1];
38502
- let sourceType = undefined;
38957
+ let sourceType;
38503
38958
  const firstAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[0];
38504
38959
  const secondAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[1];
38505
38960
  const thirdAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[2];
@@ -38515,6 +38970,19 @@ class Assign {
38515
38970
  }
38516
38971
  else {
38517
38972
  sourceType = source_1.Source.runSyntax(theSource, input, undefined, false, isComponent === false);
38973
+ if ((secondAssign === null || secondAssign === void 0 ? void 0 : secondAssign.concatTokens()) === "->"
38974
+ && (thirdAssign === null || thirdAssign === void 0 ? void 0 : thirdAssign.get()) instanceof Expressions.Dynamic
38975
+ && (sourceType === null || sourceType === void 0 ? void 0 : sourceType.isGeneric()) === true
38976
+ && !(sourceType instanceof basic_1.DataReference)
38977
+ && !(sourceType instanceof basic_1.ObjectReferenceType)
38978
+ && !(sourceType instanceof basic_1.GenericObjectReferenceType)
38979
+ && !(0, version_1.releaseAtLeast)(input.scope.getRelease(), version_1.Release.v756)
38980
+ && input.scope.getLanguageVersion() !== version_1.LanguageVersion.Cloud
38981
+ && !input.scope.getOpenABAP()) {
38982
+ const message = `"${theSource.concatTokens()}" is not a reference variable`;
38983
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
38984
+ return;
38985
+ }
38518
38986
  }
38519
38987
  if ((assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren().length) === 5
38520
38988
  && isComponent) {
@@ -43241,20 +43709,23 @@ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expr
43241
43709
  const source_1 = __webpack_require__(/*! ../expressions/source */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js");
43242
43710
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/dynamic.js");
43243
43711
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/database_table.js");
43712
+ const _check_database_work_area_1 = __webpack_require__(/*! ../expressions/_check_database_work_area */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_work_area.js");
43244
43713
  class InsertDatabase {
43245
43714
  runSyntax(node, input) {
43715
+ const sourceTypes = new Map();
43246
43716
  for (const s of node.findAllExpressions(Expressions.Source)) {
43247
- source_1.Source.runSyntax(s, input);
43717
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
43248
43718
  }
43249
43719
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
43250
- source_1.Source.runSyntax(s, input);
43720
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
43251
43721
  }
43252
43722
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
43253
43723
  dynamic_1.Dynamic.runSyntax(d, input);
43254
43724
  }
43255
43725
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
43256
43726
  if (dbtab !== undefined) {
43257
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
43727
+ const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
43728
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
43258
43729
  }
43259
43730
  }
43260
43731
  }
@@ -43840,7 +44311,7 @@ class Loop {
43840
44311
  && topType instanceof basic_1.TableType) {
43841
44312
  // https://github.com/abap2xlsx/abap2xlsx/issues/1341
43842
44313
  const keyName = node.findExpressionAfterToken("KEY");
43843
- let key = undefined;
44314
+ let key;
43844
44315
  const name = (keyName === null || keyName === void 0 ? void 0 : keyName.get()) instanceof Expressions.SimpleName ? keyName.getFirstToken().getStr().toUpperCase() : undefined;
43845
44316
  // it might be dynamic, in that case we cannot check anything; and
43846
44317
  // primary_key is the predefined name of the primary key every table has
@@ -44197,11 +44668,13 @@ const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modu
44197
44668
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/database_table.js");
44198
44669
  const source_1 = __webpack_require__(/*! ../expressions/source */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js");
44199
44670
  const _reference_1 = __webpack_require__(/*! ../_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
44671
+ const _check_database_work_area_1 = __webpack_require__(/*! ../expressions/_check_database_work_area */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_work_area.js");
44200
44672
  class ModifyDatabase {
44201
44673
  runSyntax(node, input) {
44202
44674
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
44203
44675
  dynamic_1.Dynamic.runSyntax(d, input);
44204
44676
  }
44677
+ let dbSource = undefined;
44205
44678
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
44206
44679
  if (dbtab !== undefined) {
44207
44680
  if (node.getChildren().length === 5) {
@@ -44210,19 +44683,21 @@ class ModifyDatabase {
44210
44683
  input.scope.addReference(dbtab.getFirstToken(), found, _reference_1.ReferenceType.DataWriteReference, input.filename);
44211
44684
  }
44212
44685
  else {
44213
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
44686
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
44214
44687
  }
44215
44688
  }
44216
44689
  else {
44217
- database_table_1.DatabaseTable.runSyntax(dbtab, input);
44690
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
44218
44691
  }
44219
44692
  }
44693
+ const sourceTypes = new Map();
44220
44694
  for (const s of node.findAllExpressions(Expressions.Source)) {
44221
- source_1.Source.runSyntax(s, input);
44695
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
44222
44696
  }
44223
44697
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
44224
- source_1.Source.runSyntax(s, input);
44698
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
44225
44699
  }
44700
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
44226
44701
  }
44227
44702
  }
44228
44703
  exports.ModifyDatabase = ModifyDatabase;
@@ -48122,11 +48597,13 @@ const identifier_1 = __webpack_require__(/*! ../../1_lexer/tokens/identifier */
48122
48597
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/database_table.js");
48123
48598
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/dynamic.js");
48124
48599
  const _check_database_fields_1 = __webpack_require__(/*! ../expressions/_check_database_fields */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
48600
+ const _check_database_work_area_1 = __webpack_require__(/*! ../expressions/_check_database_work_area */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_database_work_area.js");
48125
48601
  class UpdateDatabase {
48126
48602
  runSyntax(node, input) {
48603
+ let dbSource = undefined;
48127
48604
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
48128
48605
  if (dbtab !== undefined) {
48129
- const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
48606
+ dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
48130
48607
  const fields = node.findAllExpressions(Expressions.SQLFieldAndValue)
48131
48608
  .flatMap(fieldAndValue => fieldAndValue.findDirectExpressions(Expressions.SQLFieldName))
48132
48609
  .map(field => field.concatTokens().toUpperCase());
@@ -48149,15 +48626,17 @@ class UpdateDatabase {
48149
48626
  }
48150
48627
  }
48151
48628
  }
48629
+ const sourceTypes = new Map();
48152
48630
  for (const s of node.findAllExpressions(Expressions.Source)) {
48153
- source_1.Source.runSyntax(s, input);
48631
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
48154
48632
  }
48155
48633
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
48156
- source_1.Source.runSyntax(s, input);
48634
+ sourceTypes.set(s, source_1.Source.runSyntax(s, input));
48157
48635
  }
48158
48636
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
48159
48637
  dynamic_1.Dynamic.runSyntax(d, input);
48160
48638
  }
48639
+ (0, _check_database_work_area_1.checkDatabaseWorkArea)(node, dbSource, sourceTypes, input);
48161
48640
  if (input.scope.getType() === _scope_type_1.ScopeType.OpenSQL) {
48162
48641
  input.scope.pop(node.getLastToken().getEnd());
48163
48642
  }
@@ -48346,7 +48825,7 @@ class WhenType {
48346
48825
  if (nameToken === undefined) {
48347
48826
  return undefined;
48348
48827
  }
48349
- let type = undefined;
48828
+ let type;
48350
48829
  const className = nameToken.getStr().toUpperCase();
48351
48830
  const found = input.scope.existsObject(className);
48352
48831
  if (found === null || found === void 0 ? void 0 : found.id) {
@@ -53470,7 +53949,7 @@ class Attributes {
53470
53949
  return false;
53471
53950
  }
53472
53951
  parseAttribute(node, visibility, input) {
53473
- let found = undefined;
53952
+ let found;
53474
53953
  const s = node.get();
53475
53954
  if (s instanceof Statements.Data) {
53476
53955
  found = new data_1.Data().runSyntax(node, input);
@@ -55646,7 +56125,7 @@ class CDSLexer {
55646
56125
  break;
55647
56126
  case "@":
55648
56127
  // @ starts a new annotation; flush current token and start building with @
55649
- build = result.add(build, row, col, mode);
56128
+ result.add(build, row, col, mode);
55650
56129
  build = "@";
55651
56130
  break;
55652
56131
  default:
@@ -60520,7 +60999,7 @@ class Help {
60520
60999
  return content;
60521
61000
  }
60522
61001
  static dumpABAP(file, reg, textDocument, position) {
60523
- let content = "";
61002
+ let content;
60524
61003
  content = `
60525
61004
  <a href="#_tokens" rel="no-refresh">Tokens</a> |
60526
61005
  <a href="#_statements" rel="no-refresh">Statements</a> |
@@ -60553,7 +61032,7 @@ class Help {
60553
61032
  return `<h3 id="_info">Info Dump</h3><pre>` + text + "</pre>";
60554
61033
  }
60555
61034
  static cursorInformation(reg, textDocument, position, file) {
60556
- let ret = "";
61035
+ let ret;
60557
61036
  const found = _lsp_utils_1.LSPUtils.findCursor(reg, { textDocument, position });
60558
61037
  if (found !== undefined) {
60559
61038
  ret = "Statement: " + this.linkToStatement(found.snode.get()) + "<br>\n" +
@@ -64311,7 +64790,7 @@ class DataElement extends _abstract_object_1.AbstractObject {
64311
64790
  }
64312
64791
  parseType(reg) {
64313
64792
  const references = [];
64314
- let lookup = undefined;
64793
+ let lookup;
64315
64794
  this.parse();
64316
64795
  if (this.parsedXML === undefined) {
64317
64796
  lookup = { type: new Types.UnknownType("Data Element " + this.getName() + ", parser error") };
@@ -69762,6 +70241,7 @@ class Table extends _abstract_object_1.AbstractObject {
69762
70241
  PRECFIELD: field.PRECFIELD,
69763
70242
  LENG: field.LENG,
69764
70243
  INTLEN: field.INTLEN,
70244
+ INTTYPE: field.INTTYPE,
69765
70245
  DATATYPE: field.DATATYPE,
69766
70246
  DECIMALS: field.DECIMALS,
69767
70247
  KEYFLAG: field.KEYFLAG,
@@ -71280,7 +71760,7 @@ class Registry {
71280
71760
  }
71281
71761
  static abaplintVersion() {
71282
71762
  // magic, see build script "version.js"
71283
- return "2.120.71";
71763
+ return "2.120.72";
71284
71764
  }
71285
71765
  getDDICReferences() {
71286
71766
  return this.ddicReferences;
@@ -72628,7 +73108,7 @@ class AlignPseudoComments extends _abap_rule_1.ABAPRule {
72628
73108
  }
72629
73109
  const col = firstCommentToken.getStart().getCol();
72630
73110
  if (previousEnd.getCol() < expectedColumn && col !== expectedColumn) {
72631
- let fix = undefined;
73111
+ let fix;
72632
73112
  if (col < expectedColumn) {
72633
73113
  fix = edit_helper_1.EditHelper.insertAt(file, firstCommentToken.getStart(), " ".repeat(expectedColumn - col));
72634
73114
  }
@@ -72795,7 +73275,7 @@ ENDINTERFACE.`,
72795
73275
  if (f.after.getCol() === column) {
72796
73276
  continue;
72797
73277
  }
72798
- let fix = undefined;
73278
+ let fix;
72799
73279
  if (f.after.getCol() < column) {
72800
73280
  fix = edit_helper_1.EditHelper.insertAt(file, f.after, " ".repeat(column - f.after.getCol()));
72801
73281
  }
@@ -75186,7 +75666,7 @@ ENDCASE.`,
75186
75666
  if (tuples.length === 1) {
75187
75667
  return false;
75188
75668
  }
75189
- let chain = "";
75669
+ let chain;
75190
75670
  if (tuples[0].left === tuples[1].left) {
75191
75671
  chain = tuples[0].left;
75192
75672
  }
@@ -75475,7 +75955,7 @@ class CheckDDIC {
75475
75955
  this.conf = conf;
75476
75956
  }
75477
75957
  run(obj) {
75478
- let found = undefined;
75958
+ let found;
75479
75959
  if (obj instanceof Objects.DataElement
75480
75960
  || obj instanceof Objects.Domain
75481
75961
  || obj instanceof Objects.Table
@@ -76199,7 +76679,6 @@ ENDCLASS.`,
76199
76679
  this.conf = conf;
76200
76680
  }
76201
76681
  runParsed(file, obj) {
76202
- let issues = [];
76203
76682
  if (this.conf.patternKind === undefined) {
76204
76683
  this.conf.patternKind = "required";
76205
76684
  }
@@ -76220,8 +76699,7 @@ ENDCLASS.`,
76220
76699
  attributes = attributes.concat(intfDef.attributes);
76221
76700
  }
76222
76701
  }
76223
- issues = this.checkAttributes(attributes);
76224
- return issues;
76702
+ return this.checkAttributes(attributes);
76225
76703
  }
76226
76704
  checkAttributes(attr) {
76227
76705
  if (attr === undefined) {
@@ -78891,7 +79369,7 @@ Make sure to test the downported code, it might not always be completely correct
78891
79369
  if (found) {
78892
79370
  return found;
78893
79371
  }
78894
- found = this.outlineGetReferenceSimple(high, lowFile);
79372
+ found = this.outlineGetReferenceSimple(high, lowFile, highSyntax);
78895
79373
  if (found) {
78896
79374
  return found;
78897
79375
  }
@@ -79566,7 +80044,17 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
79566
80044
  const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getStart(), node.getEnd(), code);
79567
80045
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
79568
80046
  }
79569
- outlineGetReferenceSimple(node, lowFile) {
80047
+ /** the type of a reference to the source: LIKE REF TO it, or REF TO data when its type is generic,
80048
+ * as LIKE REF TO a generically typed field symbol or parameter does not activate */
80049
+ refTypeOf(sourceName, node, lowFile, highSyntax) {
80050
+ var _a;
80051
+ const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
80052
+ if (((_a = spag === null || spag === void 0 ? void 0 : spag.findVariable(sourceName)) === null || _a === void 0 ? void 0 : _a.getType().isGeneric()) === true) {
80053
+ return "TYPE REF TO data";
80054
+ }
80055
+ return "LIKE REF TO " + sourceName;
80056
+ }
80057
+ outlineGetReferenceSimple(node, lowFile, highSyntax) {
79570
80058
  var _a, _b, _c;
79571
80059
  if (!(node.get() instanceof Statements.GetReference)) {
79572
80060
  return undefined;
@@ -79583,7 +80071,8 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
79583
80071
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
79584
80072
  const firstToken = target.getFirstToken();
79585
80073
  const lastToken = target.getLastToken();
79586
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getStart(), `DATA ${targetName} LIKE REF TO ${source.concatTokens()}.\n${indentation}`);
80074
+ const refType = this.refTypeOf(source.concatTokens(), node, lowFile, highSyntax);
80075
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getStart(), `DATA ${targetName} ${refType}.\n${indentation}`);
79587
80076
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), lastToken.getEnd(), targetName);
79588
80077
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
79589
80078
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
@@ -79600,7 +80089,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
79600
80089
  if (!(((_a = target === null || target === void 0 ? void 0 : target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.InlineData)) {
79601
80090
  return undefined;
79602
80091
  }
79603
- let type = "";
80092
+ let type;
79604
80093
  const source = node.findFirstExpression(Expressions.Source);
79605
80094
  if (source === undefined) {
79606
80095
  return undefined;
@@ -79690,8 +80179,8 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
79690
80179
  if (!(node.get() instanceof Statements.Raise)) {
79691
80180
  return undefined;
79692
80181
  }
79693
- let id = undefined;
79694
- let number = undefined;
80182
+ let id;
80183
+ let number;
79695
80184
  let startToken = node.findDirectTokenByText("ID");
79696
80185
  if (startToken) {
79697
80186
  const sources = node.findDirectExpressions(Expressions.Source);
@@ -79849,7 +80338,7 @@ ${indentation}${uniqueName2}->if_t100_message~t100key = ${uniqueName1}.\n`;
79849
80338
  || sourceRef.getChildren().length !== 1) {
79850
80339
  return undefined;
79851
80340
  }
79852
- let code = "";
80341
+ let code;
79853
80342
  if (sourceRef.findFirstExpression(Expressions.TableExpression)) {
79854
80343
  const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79855
80344
  code = `ASSIGN ${sourceRef.concatTokens()} TO FIELD-SYMBOL(<${uniqueName}>).
@@ -80041,7 +80530,7 @@ LOOP AT ${groupTargetName}tab ${groupTarget}.`;
80041
80530
  || !(tableExpression instanceof nodes_1.ExpressionNode)) {
80042
80531
  return undefined;
80043
80532
  }
80044
- let condition = "";
80533
+ let condition;
80045
80534
  if (tableExpression.getChildren().length === 3) {
80046
80535
  const index = tableExpression.findDirectExpression(Expressions.Source);
80047
80536
  if (index === undefined) {
@@ -80225,7 +80714,7 @@ ${indentation}${uniqueName}`;
80225
80714
  return undefined;
80226
80715
  }
80227
80716
  const op = secondChild.getFirstToken();
80228
- let operator = "";
80717
+ let operator;
80229
80718
  switch (op.getStr()) {
80230
80719
  case "+":
80231
80720
  operator = " + ";
@@ -80267,7 +80756,7 @@ ${indentation}${uniqueName}`;
80267
80756
  || (formatting === null || formatting === void 0 ? void 0 : formatting.startsWith("ALPHA = ")) === false) {
80268
80757
  continue;
80269
80758
  }
80270
- let functionName = "";
80759
+ let functionName;
80271
80760
  switch (formatting) {
80272
80761
  case "ALPHA = IN":
80273
80762
  functionName = "CONVERSION_EXIT_ALPHA_INPUT";
@@ -80563,13 +81052,12 @@ ${indentation} output = ${uniqueName}.\n`;
80563
81052
  const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
80564
81053
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
80565
81054
  let body = "";
80566
- let name = "";
80567
81055
  const switchBody = i.findDirectExpression(Expressions.SwitchBody);
80568
81056
  if (switchBody === undefined) {
80569
81057
  continue;
80570
81058
  }
80571
81059
  for (const l of ((_c = switchBody === null || switchBody === void 0 ? void 0 : switchBody.findDirectExpression(Expressions.Let)) === null || _c === void 0 ? void 0 : _c.findDirectExpressions(Expressions.InlineFieldDefinition)) || []) {
80572
- name = l.getFirstToken().getStr();
81060
+ const name = l.getFirstToken().getStr();
80573
81061
  body += indentation + `DATA(${name}) = ${(_d = switchBody.findFirstExpression(Expressions.Source)) === null || _d === void 0 ? void 0 : _d.concatTokens()}.\n`;
80574
81062
  }
80575
81063
  body += `DATA ${uniqueName} ${type}.\n`;
@@ -80627,7 +81115,6 @@ ${indentation} output = ${uniqueName}.\n`;
80627
81115
  const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
80628
81116
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
80629
81117
  let body = "";
80630
- let name = "";
80631
81118
  const reduceBody = i.findDirectExpression(Expressions.ReduceBody);
80632
81119
  if (reduceBody === undefined) {
80633
81120
  continue;
@@ -80638,7 +81125,7 @@ ${indentation} output = ${uniqueName}.\n`;
80638
81125
  }
80639
81126
  let firstName = "";
80640
81127
  for (const init of reduceBody.findDirectExpressions(Expressions.InlineFieldDefinition)) {
80641
- name = init.getFirstToken().getStr();
81128
+ const name = init.getFirstToken().getStr();
80642
81129
  if (firstName === "") {
80643
81130
  firstName = name;
80644
81131
  }
@@ -80870,7 +81357,7 @@ ${indentation} output = ${uniqueName}.\n`;
80870
81357
  after += c.concatTokens();
80871
81358
  }
80872
81359
  }
80873
- let condition = "";
81360
+ let condition;
80874
81361
  if ((tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.getChildren().length) === 3) {
80875
81362
  condition = "INDEX " + ((_d = tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.findDirectExpression(Expressions.Source)) === null || _d === void 0 ? void 0 : _d.concatTokens());
80876
81363
  }
@@ -81021,7 +81508,7 @@ ${indentation} output = ${uniqueName}.\n`;
81021
81508
  continue;
81022
81509
  }
81023
81510
  const name = nameToken.getStr();
81024
- let type = "";
81511
+ let type;
81025
81512
  if (high.concatTokens().toUpperCase().startsWith("APPEND INITIAL LINE TO ")) {
81026
81513
  type = "LIKE LINE OF " + ((_b = high.findFirstExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());
81027
81514
  }
@@ -81387,7 +81874,7 @@ ${indentation} output = ${uniqueName}.\n`;
81387
81874
  }
81388
81875
  return undefined;
81389
81876
  }
81390
- getReference(node, lowFile, _highSyntax) {
81877
+ getReference(node, lowFile, highSyntax) {
81391
81878
  var _a, _b, _c;
81392
81879
  if (!(node.get() instanceof Statements.GetReference)) {
81393
81880
  return undefined;
@@ -81401,7 +81888,7 @@ ${indentation} output = ${uniqueName}.\n`;
81401
81888
  if (targetName === undefined || sourceName === undefined) {
81402
81889
  return undefined;
81403
81890
  }
81404
- const code = `DATA ${targetName} LIKE REF TO ${sourceName}.\n`;
81891
+ const code = `DATA ${targetName} ${this.refTypeOf(sourceName, node, lowFile, highSyntax)}.\n`;
81405
81892
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);
81406
81893
  const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inline.getFirstToken().getStart(), inline.getLastToken().getEnd(), targetName);
81407
81894
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
@@ -81478,18 +81965,30 @@ ${indentation} output = ${uniqueName}.\n`;
81478
81965
  const uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
81479
81966
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
81480
81967
  const sy = func === "LINE_EXISTS" ? "sy-subrc" : "sy-tabix";
81481
- const code = `DATA ${uniqueName} LIKE sy-subrc.\n` +
81482
- indentation + `READ TABLE ${tableName} ${condition}TRANSPORTING NO FIELDS.\n` +
81483
- indentation + uniqueName + ` = ${sy}.\n` +
81484
- indentation;
81485
81968
  let insertAt = node.getFirstToken().getStart();
81486
81969
  if (node.get() instanceof statements_1.ElseIf) {
81487
- // assumption: no side effects in IF conditions
81970
+ // assumption: no side effects in IF conditions, except the READ itself, see below
81488
81971
  insertAt = this.findStartOfIf(node, highFile);
81489
81972
  if (insertAt === undefined) {
81490
81973
  continue;
81491
81974
  }
81492
81975
  }
81976
+ // the READ sets sy-subrc and sy-tabix, which the built-in function does not,
81977
+ // keep the values for the code that reads them after the inserted READ
81978
+ const keep = [];
81979
+ const reads = this.readSyFields(insertAt, highFile);
81980
+ for (const field of ["sy-subrc", "sy-tabix"]) {
81981
+ if (reads.has(field)) {
81982
+ keep.push({ field, name: this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax) });
81983
+ }
81984
+ }
81985
+ const code = `DATA ${uniqueName} LIKE sy-subrc.\n` +
81986
+ keep.map(k => indentation + `DATA ${k.name} LIKE ${k.field}.\n`).join("") +
81987
+ keep.map(k => indentation + `${k.name} = ${k.field}.\n`).join("") +
81988
+ indentation + `READ TABLE ${tableName} ${condition}TRANSPORTING NO FIELDS.\n` +
81989
+ indentation + uniqueName + ` = ${sy}.\n` +
81990
+ keep.map(k => indentation + `${k.field} = ${k.name}.\n`).join("") +
81991
+ indentation;
81493
81992
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, insertAt, code);
81494
81993
  const start = expression.getFirstToken().getStart();
81495
81994
  const end = expression.getLastToken().getEnd();
@@ -81500,6 +81999,46 @@ ${indentation} output = ${uniqueName}.\n`;
81500
81999
  }
81501
82000
  return undefined;
81502
82001
  }
82002
+ /** sy-subrc and sy-tabix, when read from the position on, in the procedure around it or the file outside of one;
82003
+ * inside a loop from the start of the outermost loop, as the next pass reads what this one left */
82004
+ readSyFields(position, highFile) {
82005
+ const structure = highFile.getStructure();
82006
+ const contains = (s) => !position.isBefore(s.getFirstToken().getStart())
82007
+ && !position.isAfter(s.getLastToken().getStart());
82008
+ let scope = undefined;
82009
+ for (const s of [Structures.Method, Structures.Form, Structures.FunctionModule]) {
82010
+ for (const p of (structure === null || structure === void 0 ? void 0 : structure.findAllStructuresRecursive(s)) || []) {
82011
+ if (contains(p)) {
82012
+ scope = p;
82013
+ }
82014
+ }
82015
+ }
82016
+ scope = scope || structure;
82017
+ let from = position;
82018
+ for (const s of [Structures.Loop, Structures.Do, Structures.While, Structures.Select]) {
82019
+ for (const l of (scope === null || scope === void 0 ? void 0 : scope.findAllStructuresRecursive(s)) || []) {
82020
+ if (contains(l) && l.getFirstToken().getStart().isBefore(from)) {
82021
+ from = l.getFirstToken().getStart();
82022
+ }
82023
+ }
82024
+ }
82025
+ const ret = new Set();
82026
+ for (const s of (scope === null || scope === void 0 ? void 0 : scope.findAllStatementNodes()) || []) {
82027
+ if (s.getLastToken().getStart().isBefore(from)) {
82028
+ continue;
82029
+ }
82030
+ const tokens = s.getTokens();
82031
+ for (let i = 0; i < tokens.length - 2; i++) {
82032
+ if (tokens[i].getStr().toUpperCase() === "SY" && tokens[i + 1].getStr() === "-") {
82033
+ const field = "sy-" + tokens[i + 2].getStr().toLowerCase();
82034
+ if (field === "sy-subrc" || field === "sy-tabix") {
82035
+ ret.add(field);
82036
+ }
82037
+ }
82038
+ }
82039
+ }
82040
+ return ret;
82041
+ }
81503
82042
  findStartOfIf(node, highFile) {
81504
82043
  const structure = highFile.getStructure();
81505
82044
  for (const c of (structure === null || structure === void 0 ? void 0 : structure.findAllStructuresRecursive(Structures.If)) || []) {
@@ -81512,6 +82051,7 @@ ${indentation} output = ${uniqueName}.\n`;
81512
82051
  return undefined;
81513
82052
  }
81514
82053
  newToCreateObject(low, high, lowFile, highSyntax) {
82054
+ var _a;
81515
82055
  if (!(low.get() instanceof _statement_1.Unknown)) {
81516
82056
  return undefined;
81517
82057
  }
@@ -81527,7 +82067,7 @@ ${indentation} output = ${uniqueName}.\n`;
81527
82067
  && found
81528
82068
  && source.concatTokens() === found.concatTokens()
81529
82069
  && target.findDirectExpression(Expressions.InlineData) === undefined) {
81530
- const abap = this.newParameters(found, target.concatTokens(), highSyntax, lowFile);
82070
+ const abap = (_a = this.newDataReference(high, target, found, lowFile, highSyntax)) !== null && _a !== void 0 ? _a : this.newParameters(found, target.concatTokens(), highSyntax, lowFile);
81531
82071
  if (abap !== undefined) {
81532
82072
  fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), abap);
81533
82073
  }
@@ -81566,6 +82106,42 @@ ${indentation} output = ${uniqueName}.\n`;
81566
82106
  return undefined;
81567
82107
  }
81568
82108
  }
82109
+ /** NEW into a data reference creates data, CREATE OBJECT cannot: "target = NEW #|type( [value] )"
82110
+ * with a variable typed REF TO a data type becomes CREATE DATA plus the assignment of the value */
82111
+ newDataReference(high, target, found, lowFile, highSyntax) {
82112
+ var _a, _b, _c;
82113
+ if (target.getChildren().length !== 1 || !(((_a = target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.TargetField)) {
82114
+ return undefined;
82115
+ }
82116
+ const children = found.getChildren();
82117
+ const value = found.findDirectExpression(Expressions.Source);
82118
+ // NEW, the type, "(", optionally one value, ")"
82119
+ if (children.length !== 4 + (value ? 1 : 0)) {
82120
+ return undefined;
82121
+ }
82122
+ const name = target.concatTokens();
82123
+ const spag = highSyntax.spaghetti.lookupPosition(high.getFirstToken().getStart(), lowFile.getFilename());
82124
+ const type = (_b = spag === null || spag === void 0 ? void 0 : spag.findVariable(name)) === null || _b === void 0 ? void 0 : _b.getType();
82125
+ if (!(type instanceof basic_1.DataReference)) {
82126
+ return undefined;
82127
+ }
82128
+ const typeName = (_c = found.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _c === void 0 ? void 0 : _c.concatTokens();
82129
+ const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
82130
+ let abap = `CREATE DATA ${name}` + (typeName === "#" ? "" : ` TYPE ${typeName}`) + ".";
82131
+ if (value === undefined) {
82132
+ return abap;
82133
+ }
82134
+ else if (type.getType().isGeneric() === false) {
82135
+ return abap + `\n${indentation}${name}->* = ${value.concatTokens()}.`;
82136
+ }
82137
+ // a generic reference cannot be dereferenced as a target below v756
82138
+ const fs = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
82139
+ abap = `FIELD-SYMBOLS ${fs} TYPE any.\n` +
82140
+ indentation + abap + "\n" +
82141
+ indentation + `ASSIGN ${name}->* TO ${fs}.\n` +
82142
+ indentation + `${fs} = ${value.concatTokens()}.`;
82143
+ return abap;
82144
+ }
81569
82145
  newParameters(found, name, highSyntax, lowFile) {
81570
82146
  var _a, _b, _c;
81571
82147
  const typeToken = (_a = found.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
@@ -82357,6 +82933,8 @@ class EmptyStructureConf extends _basic_rule_config_1.BasicRuleConfig {
82357
82933
  this.try = true;
82358
82934
  /** Checks for empty WHEN blocks */
82359
82935
  this.when = true;
82936
+ /** Checks for empty CATCH blocks, unless the CATCH has pragma ##NO_HANDLER or pseudo comment "#EC NO_HANDLER */
82937
+ this.catch = false;
82360
82938
  // todo, other category containing ELSE
82361
82939
  }
82362
82940
  }
@@ -82469,6 +83047,21 @@ result = xsdbool( sy-subrc = 0 ).`,
82469
83047
  }
82470
83048
  }
82471
83049
  }
83050
+ if (this.getConfig().catch === true) {
83051
+ for (const c of stru.findAllStructuresRecursive(Structures.Catch)) {
83052
+ // a comment in the block does not count, the extended check (SLIN) reports it too
83053
+ if (c.findDirectStructure(Structures.Body) !== undefined) {
83054
+ continue;
83055
+ }
83056
+ const catchStatement = c.getFirstStatement();
83057
+ if (catchStatement === undefined || this.isNoHandler(catchStatement, statements)) {
83058
+ continue;
83059
+ }
83060
+ const token = c.getFirstToken();
83061
+ const issue = issue_1.Issue.atToken(file, token, this.getDescription(c.get().constructor.name), this.getMetadata().key, this.conf.severity);
83062
+ issues.push(issue);
83063
+ }
83064
+ }
82472
83065
  if (this.getConfig().when === true) {
82473
83066
  const tries = stru.findAllStructuresRecursive(Structures.When);
82474
83067
  for (const t of tries) {
@@ -82482,6 +83075,15 @@ result = xsdbool( sy-subrc = 0 ).`,
82482
83075
  }
82483
83076
  return issues;
82484
83077
  }
83078
+ isNoHandler(catchStatement, statements) {
83079
+ if (catchStatement.getPragmas().some(p => p.getStr().toUpperCase() === "##NO_HANDLER")) {
83080
+ return true;
83081
+ }
83082
+ const next = statements[statements.indexOf(catchStatement) + 1];
83083
+ return (next === null || next === void 0 ? void 0 : next.get()) instanceof _statement_1.Comment
83084
+ && next.getStart().getRow() === catchStatement.getEnd().getRow()
83085
+ && next.concatTokens().toUpperCase().replace(/\s/g, "").includes("\"#ECNO_HANDLER");
83086
+ }
82485
83087
  }
82486
83088
  exports.EmptyStructure = EmptyStructure;
82487
83089
  //# sourceMappingURL=empty_structure.js.map
@@ -83918,7 +84520,7 @@ cl_abap_typedescr=>describe_by_name(
83918
84520
  const methodSource = statNode.findDirectExpression(Expressions.MethodSource);
83919
84521
  let methodSourceStr = methodSource === null || methodSource === void 0 ? void 0 : methodSource.concatTokens();
83920
84522
  const methodBody = statNode.findDirectExpression(Expressions.MethodCallBody);
83921
- let methodBodyStr = "";
84523
+ let methodBodyStr;
83922
84524
  if (methodBody) {
83923
84525
  const methodCallParam = methodBody.findDirectExpression(Expressions.MethodCallParam);
83924
84526
  if (methodCallParam && methodCallParam.getFirstToken().getStr() === "(") {
@@ -86812,7 +87414,7 @@ class KeywordCase extends _abap_rule_1.ABAPRule {
86812
87414
  const firstToken = tokens[0].token;
86813
87415
  const lastToken = tokens[tokens.length - 1].token;
86814
87416
  const firstTokenValue = firstToken.getStr();
86815
- let description = "";
87417
+ let description;
86816
87418
  if (first.keyword === true) {
86817
87419
  description = `Keyword should be ${this.conf.style} case: "${firstTokenValue}"`;
86818
87420
  }
@@ -87337,7 +87939,7 @@ ENDCLASS.`,
87337
87939
  continue;
87338
87940
  }
87339
87941
  const className = classDef.name;
87340
- let expected = "";
87942
+ let expected;
87341
87943
  if (classDef.isForTesting) {
87342
87944
  expected = this.conf.test;
87343
87945
  }
@@ -88003,7 +88605,7 @@ ENDIF.
88003
88605
  issues.push(...this.analyzeCondition(file, cond));
88004
88606
  }
88005
88607
  for (const sub of structure.findAllExpressionsMulti([Expressions.CondSub, Expressions.ComponentCondSub])) {
88006
- let cond = [];
88608
+ let cond;
88007
88609
  if (sub.get() instanceof Expressions.CondSub) {
88008
88610
  cond = sub.findDirectExpressions(Expressions.Cond);
88009
88611
  }
@@ -92041,13 +92643,9 @@ ENDIF.`,
92041
92643
  }
92042
92644
  else if (statement instanceof Statements.ClassDefinitionLoad ||
92043
92645
  statement instanceof Statements.InterfaceLoad) {
92044
- let token = undefined;
92045
- if (statement instanceof Statements.ClassDefinitionLoad) {
92046
- token = statementNode.getChildren()[3].getFirstToken();
92047
- }
92048
- else {
92049
- token = statementNode.getChildren()[2].getFirstToken();
92050
- }
92646
+ const token = statement instanceof Statements.ClassDefinitionLoad
92647
+ ? statementNode.getChildren()[3].getFirstToken()
92648
+ : statementNode.getChildren()[2].getFirstToken();
92051
92649
  let startPosition = token.getStart();
92052
92650
  startPosition = new position_1.Position(startPosition.getRow(), startPosition.getCol() - 1);
92053
92651
  return edit_helper_1.EditHelper.deleteRange(file, startPosition, token.getEnd());
@@ -92844,7 +93442,6 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
92844
93442
  exports.ParserMissingSpace = exports.ParserMissingSpaceConf = void 0;
92845
93443
  const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
92846
93444
  const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
92847
- const position_1 = __webpack_require__(/*! ../position */ "./node_modules/@abaplint/core/build/src/position.js");
92848
93445
  const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@abaplint/core/build/src/rules/_abap_rule.js");
92849
93446
  const nodes_1 = __webpack_require__(/*! ../abap/nodes */ "./node_modules/@abaplint/core/build/src/abap/nodes/index.js");
92850
93447
  const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
@@ -92877,7 +93474,7 @@ This rule makes sure the spaces are consistently required across the language.`,
92877
93474
  }
92878
93475
  runParsed(file) {
92879
93476
  const issues = [];
92880
- let start = new position_1.Position(0, 0);
93477
+ let start;
92881
93478
  for (const statement of file.getStatements()) {
92882
93479
  const missing = this.missingSpace(statement);
92883
93480
  if (missing) {
@@ -94438,14 +95035,8 @@ From 752 and up`,
94438
95035
  }
94439
95036
  getFix(file, statement, withExporting) {
94440
95037
  const children = statement.getChildren();
94441
- let contentFix = undefined;
94442
- if (withExporting) {
94443
- const fixText = "( " + children[5].concatTokens() + " ).";
94444
- contentFix = edit_helper_1.EditHelper.replaceRange(file, children[3].getLastToken().getEnd(), statement.getEnd(), fixText);
94445
- }
94446
- else {
94447
- contentFix = edit_helper_1.EditHelper.replaceRange(file, children[3].getLastToken().getEnd(), statement.getEnd(), "( ).");
94448
- }
95038
+ const fixText = withExporting ? "( " + children[5].concatTokens() + " )." : "( ).";
95039
+ const contentFix = edit_helper_1.EditHelper.replaceRange(file, children[3].getLastToken().getEnd(), statement.getEnd(), fixText);
94449
95040
  const replaceType = edit_helper_1.EditHelper.replaceToken(file, children[2].getFirstToken(), "NEW");
94450
95041
  return edit_helper_1.EditHelper.merge(contentFix, replaceType);
94451
95042
  }
@@ -102872,6 +103463,7 @@ class XMLConsistency {
102872
103463
  * Naming for CLAS and INTF objects
102873
103464
  * QUAN fields in TABL objects have reference table and field values
102874
103465
  * Transparent TABL objects have delivery class and size category set
103466
+ * TABL fields with a built-in type carry the INTTYPE abapGit serializes for it, for the confirmed pairs
102875
103467
  * Lock parameter names in ENQU objects are max 16 characters
102876
103468
  * Texts and translations do not exceed maximum allowed length.`,
102877
103469
  tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax],
@@ -103138,6 +103730,12 @@ class XMLConsistency {
103138
103730
  const message = `QUAN field ${field.FIELDNAME} must have REFTABLE and REFFIELD set`;
103139
103731
  issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
103140
103732
  }
103733
+ const expected = field.DATATYPE ? XMLConsistency.intTypes[field.DATATYPE] : undefined;
103734
+ if (expected !== undefined && field.INTTYPE !== undefined && field.INTTYPE !== expected) {
103735
+ const message = `Field ${field.FIELDNAME}: INTTYPE "${field.INTTYPE}" does not match DATATYPE ${field.DATATYPE}, ` +
103736
+ `abapGit serializes "${expected}"`;
103737
+ issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
103738
+ }
103141
103739
  }
103142
103740
  if (obj.getTableCategory() === Objects.TableCategory.Transparent) {
103143
103741
  // Confirmed reserved database field names, see issue #4331, DAY and HOUR reported by activation.
@@ -103161,6 +103759,15 @@ class XMLConsistency {
103161
103759
  }
103162
103760
  }
103163
103761
  exports.XMLConsistency = XMLConsistency;
103762
+ // INTTYPE that abapGit serializes for a built-in DATATYPE, confirmed by exported tables;
103763
+ // a different value activates, but shows as a diff on every pull
103764
+ XMLConsistency.intTypes = {
103765
+ "CHAR": "C", "CLNT": "C", "CUKY": "C", "LANG": "C",
103766
+ "DATS": "D", "TIMS": "T",
103767
+ "INT4": "X", "RAW": "X",
103768
+ "DEC": "P", "CURR": "P",
103769
+ "STRG": "g", "SSTR": "g", "RSTR": "y",
103770
+ };
103164
103771
  //# sourceMappingURL=xml_consistency.js.map
103165
103772
 
103166
103773
  /***/ },
@@ -103783,7 +104390,7 @@ class FormLengthStats {
103783
104390
  return res;
103784
104391
  }
103785
104392
  static findName(stat) {
103786
- let name = "";
104393
+ let name;
103787
104394
  const nameExpr = stat.findFirstExpression(expressions_1.FormName);
103788
104395
  if (nameExpr) {
103789
104396
  name = nameExpr.getFirstToken().getStr();
@@ -104194,7 +104801,7 @@ class MethodLengthStats {
104194
104801
  return res;
104195
104802
  }
104196
104803
  static findName(stat) {
104197
- let name = "";
104804
+ let name;
104198
104805
  const nameExpr = stat.findFirstExpression(expressions_1.MethodName);
104199
104806
  if (nameExpr) {
104200
104807
  name = nameExpr.getFirstToken().getStr();
@@ -127051,13 +127658,20 @@ class Traversal {
127051
127658
  if (ref === undefined) {
127052
127659
  return undefined;
127053
127660
  }
127054
- // local
127661
+ // local, also when the interface is declared in another include of the same object,
127662
+ // eg. a local interface in the locals_imp of a class, used in its test classes
127055
127663
  if (ref.getFilename() === this.getFilename()) {
127056
127664
  const scope = this.findCurrentScopeByToken(ref.getToken());
127057
127665
  if (scope?.getIdentifier().stype === abaplint.ScopeType.Interface) {
127058
127666
  return scope?.getIdentifier().sname;
127059
127667
  }
127060
127668
  }
127669
+ else if (this.getCurrentObject().getABAPFileByName(ref.getFilename()) !== undefined) {
127670
+ const scope = this.spaghetti.lookupPosition(ref.getStart(), ref.getFilename());
127671
+ if (scope?.getIdentifier().stype === abaplint.ScopeType.Interface) {
127672
+ return scope?.getIdentifier().sname;
127673
+ }
127674
+ }
127061
127675
  // global
127062
127676
  for (const obj of this.reg.getObjectsByType("INTF")) {
127063
127677
  if (obj.getFiles().some(f => f.getFilename() === ref.getFilename())) {
@@ -127422,8 +128036,33 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
127422
128036
  return `abap.Classes['${name}'] = ${Traversal.escapeNamespace(def.getName().toLowerCase())};`;
127423
128037
  }
127424
128038
  setValues(identifier, name) {
128039
+ // an enumerated value of a class or interface, declared without STRUCTURE: number the
128040
+ // values in the order they are declared, like the STRUCTURE components in setValues below
128041
+ if (identifier.getValue() === "novalueClassAttributeEnum"
128042
+ && !(identifier.getType() instanceof abaplint.BasicTypes.StructureType)) {
128043
+ const index = this.findEnumValueIndex(identifier);
128044
+ return index === undefined ? "" : Traversal.prefixVariable(name) + ".set(" + index + ");\n";
128045
+ }
127425
128046
  return Traversal.setValues(identifier, name);
127426
128047
  }
128048
+ /** position of an enumerated value in its TYPES BEGIN OF ENUM, counting from 0 */
128049
+ findEnumValueIndex(identifier) {
128050
+ // the enum can be declared in another object, eg. a global interface the class implements
128051
+ const filename = identifier.getFilename();
128052
+ const raw = this.reg.getFileByName(filename);
128053
+ const obj = raw === undefined ? undefined : this.reg.findObjectForFile(raw);
128054
+ const file = obj instanceof abaplint.ABAPObject ? obj.getABAPFileByName(filename) : undefined;
128055
+ for (const enumeration of file?.getStructure()?.findAllStructures(abaplint.Structures.TypeEnum) || []) {
128056
+ const values = enumeration.getChildren().filter(c => c instanceof abaplint.Nodes.StatementNode
128057
+ && (c.get() instanceof abaplint.Statements.Type || c.get() instanceof abaplint.Statements.TypeEnum));
128058
+ const index = values.findIndex(v => v
128059
+ .findFirstExpression(abaplint.Expressions.NamespaceSimpleName)?.getFirstToken().getStart().equals(identifier.getStart()));
128060
+ if (index >= 0) {
128061
+ return index;
128062
+ }
128063
+ }
128064
+ return undefined;
128065
+ }
127427
128066
  static setValues(identifier, name) {
127428
128067
  const val = identifier.getValue();
127429
128068
  let ret = "";
@@ -127819,6 +128458,11 @@ run().then(() => {
127819
128458
  }
127820
128459
  methods.push(m.name);
127821
128460
  }
128461
+ if (methods.length === 0) {
128462
+ // FOR TESTING helper class without test methods, nothing to run; it might also
128463
+ // live in locals_imp, which is not exported from the .testclasses module
128464
+ continue;
128465
+ }
127822
128466
  tests.push({
127823
128467
  obj,
127824
128468
  filename: `${(0, output_layout_1.importPath)("index.mjs", this.layout.objectModule(obj, ".testclasses"))}`,