如何在 TypeScript 中获取源代码中的实际行号(用于自定义日志记录)

How to get actual line # within source (for custom logging) in TypeScript

引用 this question 我正在使用这段代码来查找调用者对我的自定义日志记录函数的行号:

/**
 * eLog - displays calling line number & message & dumps vars as pretty json string
 * @param {string} msg - string to display in log message
 * @param {any} dispVars - any number of variables (ellipsis , aka Rest parameters) to dump
 */
function eLog(msg:string,...dispVars:any[]){
    let caller_line = (new Error).stack.split("\n")[4];
    console.log(`eLog->Line#${caller_line}->${msg}->`);
    console.log(JSON.stringify((new Error).stack.split("\n"),null,2));
    dispVars.forEach(value => {
        console.log(JSON.stringify(value,null,2));
    });
}

这样调用:

eLog("eLog Test",this);

虽然这确实正确转储了 .js 文件行 #,但我需要源代码行 #,.ts 行号。我怎样才能正确生成它?

How can I generate this properly

a.) 您拥有的代码相当依赖于用户运行时(例如,将无法在 IE 中运行)。

b.) 您将需要 js -> ts 的源映射才能工作。使它变得简单的东西还不存在。 事实上 使用 sourcemaps 的原始包是:https://www.npmjs.com/package/source-map

我整个晚上都在研究这个,想出了一个我很满意的函数。感谢您的入门帮助-

把它分成log.ts

require('source-map-support').install({
 environment: 'node'
});


/**
 * eLog - displays calling line number & message & dumps vars as pretty json string
 * @param {string} msg - string to display in log message
 * @param {any} dispVars - any number of variables (ellipsis , aka Rest parameters) to dump
 * {@link https://github.com/evanw/node-source-map-support usable by typescript node-source-map-support module}
 * {@link https://github.com/mozilla/source-map/ Mozilla source-map library & project}
 * {@link http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/ good introduction to sourcemaps}
 */
export function eLog(msg:string,...dispVars:any[]){
 /**
  * go one line back for the caller
  * @type {string}
  */
 let stackLine = (new Error).stack.split("\n")[2];
 /**
  * retrieve the file basename & positional data, after the last `/` to the `)` 
  */
 // 
 let caller_line = stackLine.slice(stackLine.lastIndexOf('/'),stackLine.lastIndexOf(')'))
 /**
  *  test for no `/` ; if there is no `/` then use filename without a prefixed path
  */ 
 if ( caller_line.length == 0 ) {
  caller_line = stackLine.slice(stackLine.lastIndexOf('('),stackLine.lastIndexOf(')'))
 }
 // 
 /**
  * filename_base - parse out the file basename; remove first `/` char and go to `:`
  */
 let filename_base = caller_line.slice(0+1,caller_line.indexOf(':'));
 /**
  * line_no - parse out the line number ; remove first `:` char and go to 2nd `:`
  */
 let line_no = caller_line.slice(caller_line.indexOf(':')+1,caller_line.lastIndexOf(':'));
 /**
  * line_pos - line positional - from the last `:` to the end of the string
  */
 let line_pos = caller_line.slice(caller_line.lastIndexOf(':')+1);
 console.log(`eLog called by ${filename_base} on line# ${line_no} @ char# ${line_pos} said:\n${msg}`);
 // print out the input variables as pretty JSON strings
 dispVars.forEach(value => {
  console.log(JSON.stringify(value,null,2));
 });
}

可以用一个简单的方式调用:

eLog("eLog Test",this);

从任何文件加载函数(例如)

import { eLog } from './log'

希望对其他人有所帮助。

干杯伙计们。 -埃里克