entkapp 4.5.1 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,125 +1,49 @@
1
- import fs from 'fs/promises';
1
+ import fs from 'fs';
2
2
  import path from 'path';
3
3
 
4
- /**
5
- * Advanced TSConfig / JSConfig Compilation Path Alias Mapper
6
- * Resolves deeply nested route mappings, wildcards, and base URL overrides.
7
- */
8
4
  export class PathMapper {
9
- constructor(context) {
10
- this.context = context;
11
- this.baseUrl = '.';
12
- this.absoluteBaseUrl = context.cwd;
13
- this.mappings = []; // Collection of { prefix, suffix, targets[] }
5
+ constructor(context) {
6
+ this.context = context;
14
7
  }
15
-
16
- /**
17
- * Reads, cleans, and indexes custom alias entries from tsconfig.json files.
18
- * @param {string} tsconfigFilename - Target designator (typically tsconfig.json)
19
- */
20
- async loadMappings(tsconfigFilename = 'tsconfig.json') {
21
- const configPath = path.resolve(this.context.cwd, tsconfigFilename);
22
-
23
- try {
24
- await fs.access(configPath);
25
- const rawText = await fs.readFile(configPath, 'utf8');
26
-
27
- // Strip inline single-line and block comments before parsing
28
- // Improved regex to handle more edge cases in tsconfig comments
29
- const jsonCleanText = rawText
30
- .replace(/\/\*[\s\S]*?\*\/|(?<=[^\\:])\/\/.*$/gm, '')
31
- .replace(/,(\s*[\]}])/g, '$1'); // Remove trailing commas
32
-
33
- const tsconfig = JSON.parse(jsonCleanText);
34
-
35
- if (!tsconfig.compilerOptions) return;
36
-
37
- const opts = tsconfig.compilerOptions;
38
-
39
- // v6 Path Resolution Fix (Knip Issue #1794)
40
- // Ensure baseUrl is correctly resolved relative to the tsconfig file location
41
- const configDir = path.dirname(configPath);
42
- if (opts.baseUrl) {
43
- this.baseUrl = opts.baseUrl;
44
- this.absoluteBaseUrl = path.resolve(configDir, this.baseUrl);
45
- } else {
46
- this.absoluteBaseUrl = configDir;
47
- }
48
-
49
- if (opts.paths) {
50
- for (const [aliasPattern, targetArrays] of Object.entries(opts.paths)) {
51
- this.registerPatternRule(aliasPattern, targetArrays);
52
- }
53
- }
54
- } catch (error) {
55
- if (this.context.verbose) {
56
- console.warn(`⚠️ [PathMapper Override] Proceeding without custom path configurations. Source: ${error.message}`);
57
- }
58
- }
8
+
9
+ async loadMappings() {
10
+ // Hier können später tsconfig-Pfade geladen werden
59
11
  }
60
12
 
61
13
  /**
62
- * Registers structural lookup parameters for alias strings.
14
+ * Resolves physical module paths on disk, translating modern .js imports
15
+ * back to their actual TypeScript source files.
16
+ * @param {string} p - The target module specifier or absolute path
63
17
  */
64
- registerPatternRule(pattern, targets) {
65
- const wildcardIndex = pattern.indexOf('*');
18
+ resolvePath(p) {
19
+ if (!p || typeof p !== 'string') return p;
66
20
 
67
- if (wildcardIndex === -1) {
68
- this.mappings.push({
69
- isExact: true,
70
- pattern,
71
- targets: targets.map(t => path.normalize(t))
72
- });
73
- return;
21
+ // FIX 1: Wenn der Import auf .js endet, übersetze ihn für die Suche auf .ts
22
+ if (p.endsWith('.js')) {
23
+ const tsPath = p.slice(0, -3) + '.ts';
24
+ if (fs.existsSync(tsPath)) return tsPath;
74
25
  }
75
26
 
76
- const prefix = pattern.slice(0, wildcardIndex);
77
- const suffix = pattern.slice(wildcardIndex + 1);
78
-
79
- this.mappings.push({
80
- isExact: false,
81
- prefix,
82
- suffix,
83
- targets: targets.map(t => path.normalize(t))
84
- });
85
- }
86
-
87
- /**
88
- * Resolves a raw import specifier against mapped path patterns.
89
- * @param {string} specifier - Raw text from import declaration (e.g., '@ui/button')
90
- * @returns {Array<string>} Candidates of absolute filesystem paths to try resolving
91
- */
92
- resolveCandidatePaths(specifier) {
93
- const matchingCandidates = [];
94
-
95
- for (const rule of this.mappings) {
96
- if (rule.isExact) {
97
- if (specifier === rule.pattern) {
98
- rule.targets.forEach(target => {
99
- matchingCandidates.push(path.resolve(this.absoluteBaseUrl, target));
100
- });
101
- }
102
- } else {
103
- // Evaluate wildcard pattern matches
104
- if (specifier.startsWith(rule.prefix) && specifier.endsWith(rule.suffix)) {
105
- const extractedWildcardContent = specifier.slice(
106
- rule.prefix.length,
107
- specifier.length - rule.suffix.length
108
- );
27
+ // FIX 2: Wenn der Import auf .jsx endet, übersetze ihn für die Suche auf .tsx
28
+ if (p.endsWith('.jsx')) {
29
+ const tsxPath = p.slice(0, -4) + '.tsx';
30
+ if (fs.existsSync(tsxPath)) return tsxPath;
31
+ }
109
32
 
110
- rule.targets.forEach(targetTemplate => {
111
- const interpolatedTarget = targetTemplate.replace('*', extractedWildcardContent);
112
- matchingCandidates.push(path.resolve(this.absoluteBaseUrl, interpolatedTarget));
113
- });
33
+ // FIX 3: Unterstützung für Verzeichnis-Imports (z.B. ./adapters -> ./adapters/index.ts)
34
+ try {
35
+ const stat = fs.statSync(p);
36
+ if (stat.isDirectory()) {
37
+ const extensions = ['.ts', '.tsx', '.js', '.jsx'];
38
+ for (const ext of extensions) {
39
+ const indexPath = path.join(p, `index${ext}`);
40
+ if (fs.existsSync(indexPath)) return indexPath;
114
41
  }
115
42
  }
43
+ } catch {
44
+ // Datei existiert nicht oder ist kein Verzeichnis, fahre mit Standard fort
116
45
  }
117
46
 
118
- // Fall back to direct lookup relative to the base URL
119
- if (!specifier.startsWith('.') && !path.isAbsolute(specifier)) {
120
- matchingCandidates.push(path.resolve(this.absoluteBaseUrl, specifier));
121
- }
122
-
123
- return matchingCandidates;
47
+ return p;
124
48
  }
125
49
  }
@@ -0,0 +1,76 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import ts from 'typescript';
4
+
5
+ export class TSConfigLoader {
6
+ constructor(targetDir) {
7
+ this.targetDir = targetDir;
8
+ }
9
+
10
+ /**
11
+ * Lädt und parst die tsconfig.json.
12
+ * @returns {Object|null} Parsed config oder null.
13
+ */
14
+ load() {
15
+ const configPath = path.join(this.targetDir, 'tsconfig.json');
16
+ if (!fs.existsSync(configPath)) return null;
17
+
18
+ try {
19
+ const content = fs.readFileSync(configPath, 'utf8');
20
+ const result = ts.parseConfigFileTextWithComments(configPath, content);
21
+
22
+ if (result.error) {
23
+ return null;
24
+ }
25
+
26
+ const parsed = ts.parseJsonConfigFileContent(
27
+ result.config,
28
+ ts.sys,
29
+ this.targetDir
30
+ );
31
+
32
+ return parsed;
33
+ } catch (e) {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Erstellt eine Mapping-Funktion für Aliases aus der tsconfig.
40
+ * @param {Object} parsedConfig
41
+ * @returns {Function} Mapper function.
42
+ */
43
+ getAliasMapper(parsedConfig) {
44
+ if (!parsedConfig || !parsedConfig.options || !parsedConfig.options.paths) {
45
+ return (source) => source;
46
+ }
47
+
48
+ const { paths, baseUrl } = parsedConfig.options;
49
+ const base = baseUrl ? path.resolve(this.targetDir, baseUrl) : this.targetDir;
50
+
51
+ return (source) => {
52
+ for (const pattern in paths) {
53
+ const regexPattern = pattern.replace(/\*/, '(.*)');
54
+ const regex = new RegExp(`^${regexPattern}$`);
55
+ const match = source.match(regex);
56
+
57
+ if (match) {
58
+ const replacements = paths[pattern];
59
+ for (const replacement of replacements) {
60
+ const resolvedReplacement = replacement.replace(/\*/, match[1]);
61
+ const fullPath = path.resolve(base, resolvedReplacement);
62
+
63
+ // Prüfe ob Datei existiert
64
+ const extensions = ['', '.ts', '.tsx', '.js', '.jsx'];
65
+ for (const ext of extensions) {
66
+ if (fs.existsSync(fullPath + ext)) {
67
+ return fullPath + ext;
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ return source;
74
+ };
75
+ }
76
+ }