|
17 | 17 | * behind `debugLogger`). |
18 | 18 | */ |
19 | 19 |
|
| 20 | +import { readFileSync } from 'node:fs'; |
20 | 21 | import path from 'node:path'; |
| 22 | +import { URL } from 'node:url'; |
21 | 23 |
|
22 | 24 | const CORE_SRC_MARKER = 'packages/core/src/'; |
23 | 25 | const UTILS_SRC_MARKER = 'packages/core/src/utils/'; |
24 | 26 | const CORE_PACKAGE_SPECIFIER = '@qwen-code/qwen-code-core'; |
25 | 27 | const CORE_PACKAGE_SRC_PREFIX = `${CORE_PACKAGE_SPECIFIER}/src/`; |
26 | 28 | const CORE_PACKAGE_DIST_PREFIX = `${CORE_PACKAGE_SPECIFIER}/dist/`; |
| 29 | +const CORE_PACKAGE_SUBPATH_PREFIX = `${CORE_PACKAGE_SPECIFIER}/`; |
| 30 | + |
| 31 | +// Resolve named self-reference subpaths from the package contract so this |
| 32 | +// boundary cannot drift from packages/core/package.json. |
| 33 | +const CORE_PACKAGE_EXPORTS = JSON.parse( |
| 34 | + readFileSync( |
| 35 | + new URL('../packages/core/package.json', import.meta.url), |
| 36 | + 'utf8', |
| 37 | + ), |
| 38 | +).exports; |
27 | 39 |
|
28 | 40 | // Deferred inversions, keyed by the utils-relative importer. Targets are |
29 | 41 | // relative to packages/core/src and omit their extension. See the file header |
@@ -54,6 +66,38 @@ function stripExtension(rel) { |
54 | 66 | return rel.replace(/\.(js|ts|tsx|mjs|cjs)$/, ''); |
55 | 67 | } |
56 | 68 |
|
| 69 | +function corePackageSourcePath(importedPath) { |
| 70 | + if (importedPath.startsWith(CORE_PACKAGE_SRC_PREFIX)) { |
| 71 | + return importedPath.slice(CORE_PACKAGE_SRC_PREFIX.length); |
| 72 | + } |
| 73 | + |
| 74 | + if (importedPath.startsWith(CORE_PACKAGE_DIST_PREFIX)) { |
| 75 | + const distRelative = importedPath.slice(CORE_PACKAGE_DIST_PREFIX.length); |
| 76 | + return distRelative.startsWith('src/') |
| 77 | + ? distRelative.slice('src/'.length) |
| 78 | + : distRelative; |
| 79 | + } |
| 80 | + |
| 81 | + if (!importedPath.startsWith(CORE_PACKAGE_SUBPATH_PREFIX)) { |
| 82 | + return null; |
| 83 | + } |
| 84 | + |
| 85 | + const exportKey = `./${importedPath.slice(CORE_PACKAGE_SUBPATH_PREFIX.length)}`; |
| 86 | + const exportEntry = CORE_PACKAGE_EXPORTS[exportKey]; |
| 87 | + const exportTarget = |
| 88 | + typeof exportEntry === 'string' ? exportEntry : exportEntry?.import; |
| 89 | + if (typeof exportTarget !== 'string') { |
| 90 | + return null; |
| 91 | + } |
| 92 | + if (exportTarget.startsWith('./dist/src/')) { |
| 93 | + return exportTarget.slice('./dist/src/'.length); |
| 94 | + } |
| 95 | + if (exportTarget.startsWith('./src/')) { |
| 96 | + return exportTarget.slice('./src/'.length); |
| 97 | + } |
| 98 | + return null; |
| 99 | +} |
| 100 | + |
57 | 101 | export default { |
58 | 102 | meta: { |
59 | 103 | type: 'problem', |
@@ -89,18 +133,12 @@ export default { |
89 | 133 | let resolved; |
90 | 134 | if (importedPath.startsWith('.')) { |
91 | 135 | resolved = path.resolve(path.dirname(filename), importedPath); |
92 | | - } else if (importedPath.startsWith(CORE_PACKAGE_SRC_PREFIX)) { |
93 | | - resolved = path.resolve( |
94 | | - srcRoot, |
95 | | - importedPath.slice(CORE_PACKAGE_SRC_PREFIX.length), |
96 | | - ); |
97 | | - } else if (importedPath.startsWith(CORE_PACKAGE_DIST_PREFIX)) { |
98 | | - resolved = path.resolve( |
99 | | - srcRoot, |
100 | | - importedPath.slice(CORE_PACKAGE_DIST_PREFIX.length), |
101 | | - ); |
102 | 136 | } else { |
103 | | - return; |
| 137 | + const sourcePath = corePackageSourcePath(importedPath); |
| 138 | + if (!sourcePath) { |
| 139 | + return; |
| 140 | + } |
| 141 | + resolved = path.resolve(srcRoot, sourcePath); |
104 | 142 | } |
105 | 143 |
|
106 | 144 | // Leave cross-package relative imports to no-relative-cross-package-imports. |
|
0 commit comments