Mirror: The small sibling of the graphql package, slimmed down for client-side libraries.
at v16.6.0-1 5.0 kB view raw
1import * as path from 'path'; 2import { nodeResolve } from '@rollup/plugin-node-resolve'; 3import { rollup } from 'rollup'; 4 5/** Generates a map of exports from a given graphql package to list of import locations. */ 6async function traceImports(moduleName) { 7 const basepath = path.resolve(process.cwd(), 'node_modules/', moduleName); 8 const exportMap = {}; 9 10 const resolveFile = (to, relative = '.') => { 11 const dirname = path.join('graphql/', relative, path.dirname(to)); 12 const filename = path.basename(to, '.mjs'); 13 return path.join(dirname, filename); 14 }; 15 16 const bundle = await rollup({ 17 // This contains all top-level "sub-modules" of graphql too, since not all exports of 18 // them may be exposed in the main index.mjs file. 19 input: { 20 graphql: path.join(basepath, 'index.mjs'), 21 'graphql/error': path.join(basepath, 'error/index.mjs'), 22 'graphql/execution': path.join(basepath, 'execution/index.mjs'), 23 'graphql/language': path.join(basepath, 'language/index.mjs'), 24 'graphql/subscription': path.join(basepath, 'subscription/index.mjs'), 25 'graphql/type': path.join(basepath, 'type/index.mjs'), 26 'graphql/utilities': path.join(basepath, 'utilities/index.mjs'), 27 'graphql/validation': path.join(basepath, 'validation/index.mjs'), 28 }, 29 shimMissingExports: false, 30 preserveEntrySignatures: 'allow-extension', 31 preserveSymlinks: true, 32 external: id => !/^\.{0,2}\//.test(id), 33 plugins: [ 34 nodeResolve(), 35 { 36 transform(code, id) { 37 const relative = path.relative(basepath, id); 38 const dirname = path.dirname(relative); 39 const exports = {}; 40 41 this.parse(code) 42 .body.filter(x => x.type === 'ExportNamedDeclaration') 43 .forEach(node => { 44 const from = node.source 45 ? resolveFile(node.source.value, dirname) 46 : resolveFile(relative); 47 48 node.specifiers.forEach(specifier => { 49 const { name: local } = specifier.exported; 50 exports[local] = { local, from }; 51 }); 52 53 if (node.declaration) { 54 (node.declaration.declarations || [node.declaration]).forEach(declaration => { 55 if (declaration && declaration.id) { 56 const { name: local } = declaration.id; 57 exports[local] = { local, from }; 58 } 59 }); 60 } 61 }); 62 63 exportMap[resolveFile(relative)] = exports; 64 return null; 65 }, 66 }, 67 ], 68 }); 69 70 await bundle.generate({}); 71 return exportMap; 72} 73 74function isDeclarationEqual(a, b) { 75 return a.local === b.local && a.from === b.from; 76} 77 78function mergeTraces(traces) { 79 const trace = {}; 80 81 // Iterate over all known filenames in all traces 82 const ids = new Set( 83 traces.map(trace => Object.keys(trace)).reduce((acc, names) => acc.concat(names), []) 84 ); 85 for (const id of ids) { 86 // Each file must exist in all traces 87 if (!traces.every(trace => !!trace[id])) continue; 88 89 const exports = {}; 90 91 // Iterate over all known exports in each trace's set of exports for this file 92 const exportNames = new Set( 93 traces.map(trace => Object.keys(trace[id])).reduce((acc, names) => acc.concat(names), []) 94 ); 95 for (const name of exportNames) { 96 // Each export must exist in all traces 97 if (traces.every(trace => !!trace[id][name])) { 98 // Collect known declarations and deduplicate 99 exports[name] = traces 100 .map(trace => trace[id][name]) 101 .filter((val, index, all) => { 102 const firstIndex = all.findIndex(item => isDeclarationEqual(item, val)); 103 return firstIndex === index; 104 }); 105 } 106 } 107 108 if (Object.keys(exports).length) trace[id] = exports; 109 } 110 111 // For a given declaration, find the first deepest one that works for the trace 112 // NOTE: This doesn't find the absolute deepest one, since it assumes that each 113 // export only has one functional trace 114 const resolveDeclaration = declaration => { 115 const declarations = trace[declaration.from]; 116 if (!declarations || !declarations[declaration.local]) return null; 117 for (const childDeclaration of declarations[declaration.local]) { 118 if (childDeclaration.from === declaration.from) continue; 119 const resolved = resolveDeclaration(childDeclaration); 120 if (resolved && resolved.from !== declaration.from) return resolved; 121 } 122 123 return declaration; 124 }; 125 126 // Resolve all known (and consistent) exports to a common, deepest declaration 127 const ROOT_MODULE = 'graphql/index'; 128 const exports = {}; 129 for (const local in trace[ROOT_MODULE]) 130 exports[local] = resolveDeclaration({ local, from: ROOT_MODULE }); 131 return exports; 132} 133 134export async function generateImportMap() { 135 return mergeTraces(await Promise.all([traceImports('graphql'), traceImports('graphql15')])); 136}