Created
March 17, 2023 02:10
-
-
Save brainkim/285d0c2ed69a4a158f5f576e16fdff41 to your computer and use it in GitHub Desktop.
ChatGPT implementation of resolve using node.js pseudocode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code was generated with the help of OpenAI's ChatGPT-4. | |
import * as FS from 'fs/promises'; | |
import * as Path from 'path'; | |
import {fileURLToPath, pathToFileURL} from 'url'; | |
async function resolvePackageImports(basePath, specifier, conditions) { | |
const pkgJson = JSON.parse(await FS.readFile(fileURLToPath(basePath) + '/package.json')); | |
const imports = pkgJson.imports; | |
if (typeof imports === 'object' && !Array.isArray(imports)) { | |
for (const key of Object.keys(imports)) { | |
if (key === specifier) { | |
const target = imports[key]; | |
if (typeof target === 'string') { | |
return new URL(target, basePath); | |
} else if (typeof target === 'object' && !Array.isArray(target)) { | |
for (const condition of conditions) { | |
if (target.hasOwnProperty(condition)) { | |
return new URL(target[condition], basePath); | |
} | |
} | |
} | |
} | |
} | |
} | |
throw new Error(`Import not found: ${specifier}`); | |
} | |
async function resolvePackageExports(basePath, subpath, exports, conditions) { | |
if (typeof exports === 'object' && !Array.isArray(exports)) { | |
for (const key of Object.keys(exports)) { | |
if (key === '.' || (key.startsWith('./') && subpath.startsWith(key))) { | |
const target = exports[key]; | |
if (typeof target === 'string') { | |
const resolved = new URL(target, basePath); | |
if (fileURLToPath(resolved).endsWith(subpath)) { | |
return resolved; | |
} | |
} else if (typeof target === 'object' && !Array.isArray(target)) { | |
for (const condition of conditions) { | |
if (target.hasOwnProperty(condition)) { | |
const resolved = new URL(target[condition], basePath); | |
if (fileURLToPath(resolved).endsWith(subpath)) { | |
return resolved; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
throw new Error(`Export not found: ${subpath}`); | |
} | |
function isCoreModule(moduleName) { | |
// Replace this list with the actual list of core modules for your Node.js version. | |
const coreModules = [ | |
'assert', | |
'buffer', | |
'child_process', | |
'cluster', | |
'console', | |
'constants', | |
'crypto', | |
'dgram', | |
'dns', | |
'domain', | |
'events', | |
'fs', | |
'http', | |
'https', | |
'module', | |
'net', | |
'os', | |
'path', | |
'punycode', | |
'querystring', | |
'readline', | |
'repl', | |
'stream', | |
'string_decoder', | |
'timers', | |
'tls', | |
'tty', | |
'url', | |
'util', | |
'v8', | |
'vm', | |
'zlib', | |
]; | |
return coreModules.includes(moduleName); | |
} | |
async function resolveEsmMatch(match) { | |
const resolvedPath = fileURLToPath(match); | |
try { | |
await FS.access(resolvedPath); | |
return resolvedPath; | |
} catch { | |
throw new Error(`Module not found: ${resolvedPath}`); | |
} | |
} | |
async function loadPackageImports(x, dir) { | |
const scope = await findClosestPackageScope(dir); | |
if (!scope) return null; | |
const pkgJson = JSON.parse(await FS.readFile(Path.join(scope, 'package.json'))); | |
if (!pkgJson.imports) return null; | |
const basePath = pathToFileURL(scope); | |
const match = await resolvePackageImports(basePath, x, ['node', 'require']); | |
return await resolveEsmMatch(match); | |
} | |
async function loadPackageExports(name, subpath, dir) { | |
try { | |
const pkgJsonFile = Path.join(dir, name, 'package.json'); | |
await FS.access(pkgJsonFile); | |
const pkgJson = JSON.parse(await FS.readFile(pkgJsonFile)); | |
if (!pkgJson.exports) return null; | |
const basePath = pathToFileURL(Path.join(dir, name)); | |
const match = await resolvePackageExports(basePath, '.' + subpath, pkgJson.exports, ['node', 'require']); | |
return await resolveEsmMatch(match); | |
} catch { | |
// Do nothing, continue to next step | |
} | |
return null; | |
} | |
async function loadAsFile(x) { | |
const extensions = ['', '.js', '.json', '.node']; | |
for (const ext of extensions) { | |
const file = x + ext; | |
try { | |
await FS.access(file); | |
return file; | |
} catch { | |
// Do nothing, continue to next extension | |
} | |
} | |
return null; | |
} | |
async function loadIndex(x) { | |
const extensions = ['/index.js', '/index.json', '/index.node']; | |
for (const ext of extensions) { | |
const file = x + ext; | |
try { | |
await FS.access(file); | |
return file; | |
} catch { | |
// Do nothing, continue to next extension | |
} | |
} | |
return null; | |
} | |
async function loadAsDirectory(x) { | |
const pkgJsonFile = Path.join(x, 'package.json'); | |
try { | |
await FS.access(pkgJsonFile); | |
const pkgJson = JSON.parse(await FS.readFile(pkgJsonFile)); | |
if (pkgJson.main) { | |
const mainFile = Path.join(x, pkgJson.main); | |
return (await loadAsFile(mainFile)) || (await loadIndex(mainFile)); | |
} | |
} catch { | |
// Do nothing, continue to next step | |
} | |
return await loadIndex(x); | |
} | |
async function nodeModulesPaths(start) { | |
const parts = start.split(Path.sep); | |
const dirs = []; | |
for (let i = parts.length - 1; i >= 0; i--) { | |
if (parts[i] === 'node_modules') continue; | |
const dir = Path.join(...parts.slice(0, i + 1), 'node_modules'); | |
dirs.unshift(dir); | |
} | |
// You should add global folders if needed | |
return dirs; | |
} | |
async function loadNodeModules(x, start) { | |
const dirs = await nodeModulesPaths(start); | |
for (const dir of dirs) { | |
const exportsResult = await loadPackageExports(x, dir); | |
if (exportsResult) return exportsResult; | |
const fileResult = await loadAsFile(Path.join(dir, x)); | |
if (fileResult) return fileResult; | |
const dirResult = await loadAsDirectory(Path.join(dir, x)); | |
if (dirResult) return dirResult; | |
} | |
return null; | |
} | |
async function loadPackageSelf(x, dir) { | |
const scope = await findClosestPackageScope(dir); | |
if (!scope) return null; | |
const pkgJson = JSON.parse(await FS.readFile(Path.join(scope, 'package.json'))); | |
if (!pkgJson.exports || pkgJson.name !== x.split('/')[0]) return null; | |
const basePath = pathToFileURL(scope); | |
const match = await resolvePackageExports(basePath, '.' + x.slice(pkgJson.name.length), pkgJson.exports, ['node', 'require']); | |
return await resolveEsmMatch(match); | |
} | |
async function findClosestPackageScope(dir) { | |
if (dir === Path.sep) return null; | |
try { | |
await FS.access(Path.join(dir, 'package.json')); | |
return dir; | |
} catch { | |
// Continue to parent directory | |
} | |
return await findClosestPackageScope(Path.dirname(dir)); | |
} | |
export async function resolve(x, y) { | |
if (isCoreModule(x)) { | |
return x; | |
} | |
if (x.startsWith('/')) { | |
y = Path.sep; | |
} | |
if (x.startsWith('./') || x.startsWith('/') || x.startsWith('../')) { | |
const fullPath = Path.resolve(y, x); | |
const result = | |
(await loadAsFile(fullPath)) || | |
(await loadAsDirectory(fullPath)) || | |
(await loadIndex(fullPath)); | |
if (result) return result; | |
throw new Error(`Module not found: ${x}`); | |
} | |
if (x.startsWith('#')) { | |
const result = await loadPackageImports(x, Path.dirname(y)); | |
if (result) return result; | |
throw new Error(`Module not found: ${x}`); | |
} | |
const result = | |
(await loadPackageSelf(x, Path.dirname(y))) || | |
(await loadNodeModules(x, Path.dirname(y))); | |
if (result) return result; | |
throw new Error(`Module not found: ${x}`); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment