UNPKG

shebang2-loader

Version:

A simple Webpack loader for files starting with a shebang (usually #!/usr/bin/env node)

97 lines (79 loc) 2.32 kB
const path = require('path'); const { SourceNode } = require('source-map'); function isWhiteSpace(ch) { return /[\t\r\n ]/.test(ch); } function advance(pos, ch) { if (ch === '\n') { pos.line++; pos.column = 0; } else { pos.column++; } } function buildSourceMapLineByLine(code, startLine, source) { const nodes = []; let lineBuffer = '' let currLine = startLine; const push = () => { nodes.push(new SourceNode(currLine, 0, source, lineBuffer+'\n')); } for (const ch of code) { if (ch === '\n') { if (lineBuffer.length > 0) { push(); } lineBuffer = ''; currLine++; } else { lineBuffer += ch; } } if (lineBuffer.length > 0) { push(); } return new SourceNode(null, null, source, nodes); } module.exports = function removeShebang(source, inputSourceMap) { const start = { line: 1, column: 0 }; let i = 0; // First we skip characters until we are at a character that is not empty for (; i < source.length; i++) { if (!isWhiteSpace(source[i])) { break; } advance(start, source[i]); } // If we are at the end or no shebang is present, keep things fast by returning early if (i+3 >= source.length || source.substring(i, 2) !== '#!') { this.callback(null, source, inputSourceMap); return; } // Get ready for finding the line after '#!...' const end = { ...start }; let j = i; // Skip the actual shebang line for (; j < source.length; j++) { if (source[j] === '\n') { end.line++; end.column = 0; j++; if (source[j] === '\r') { j++; end.column++; } break; } // Unnecesessary since it will be reset anyways //end.column++; } const result = source.substring(0, i) + source.substring(j); const sourcePath = path.resolve(__dirname, __filename) + '!' + this.resourcePath; // Weird ... source-map does not seem to support nodes with multi-line text in it, which is strange to say the least. const node = buildSourceMapLineByLine(result, end.line, this.resourcePath) //node.setSourceContent(sourcePath, result) node.setSourceContent(this.resourcePath, source) const generated = node.toStringWithSourceMap(); // Done! this.callback(null, generated.code, generated.map.toJSON()); }