TS/Node.js : Получение абсолютного пути к экземпляру класса, а не к самому классу

#node.js #typescript

#node.js #typescript

Вопрос:

Есть ли способ получить путь (__dirname) к файлу, в котором был создан экземпляр класса, не передавая его в конструктор? Например,

 // src/classes/A.ts
export class A {
    private instanceDirname: string;
    constructor() {
        this.instanceDirname = ??
    }
}

// src/index.ts
import { A } from "./classes/A"
const a = new A();
// a.instanceDirname === __dirname ✓
  

Я попробовал callsite, это сработало, но мне пришлось использовать некоторые регулярные выражения, которые мне не нравятся, чтобы получить то, что мне нужно, я также попробовал модуль с именем caller-callsite, но в итоге он вернул путь к модулю, а не путь к файлу, в котором был создан экземпляр.
Есть ли обходной путь для этого?

Ответ №1:

Я бы попросил вызывающих абонентов передавать информацию о местоположении. Обнюхивание этого материала кажется мне запахом кода (простите за каламбур). 😉

Но вы можете сделать это, используя регулярные выражения в стеке вызовов версии 8 из Error экземпляра, но это все равно связано с выполнением регулярных выражений (которые вам не понравились в callsite), хотя они выполняются в собственных стеках версии 8, которые вряд ли изменятся кардинальным образом (и, конечно,не будет, за исключением случаев, когда вы выполняете обновления Node.js , так что это легко проверить). См. Комментарии:

 // A regular expression to look for lines in this file (A.ts / A.js)
const rexThisFile = /bA.[tj]s:/i;

// Your class
export class A {
    constructor() {
        // Get a stack trace, break into lines -- this is V8, we can rely on the format
        const stackLines = (new Error().stack).split(/rn|r|n/);
        // Find the first line that doesn't reference this file
        const line = stackLines.find((line, index) => index > 0 amp;amp; !rexThisFile.test(line));
        if (line) {
            // Found it, extract the directory from it
            const instanceOfDirName = line.replace(/^s*ats*/, "")
                         .replace(/w .[tj]s[:d] $/, "")
                         .replace(/^file:///, "");
            console.log(`instanceOfDirName = "${instanceOfDirName}"`);
        }
    }
}
  

Эти три замены могут быть объединены:

 const instanceOfDirName = line.replace(/(?:^s*ats*(?:file://)?)|(?:w .[tj]s[:d] $)/g, "");
  

… но я оставил их отдельно для ясности; не собираюсь заботиться о какой-либо разнице в производительности.

Комментарии:

1. Близко к тому, что я делал с callsite, за исключением того, что в некоторых случаях стек содержал нулевые записи, которые меня раздражали, но я думаю, этого можно было избежать, используя V8 напрямую.. Спасибо 🙂