-
Notifications
You must be signed in to change notification settings - Fork 37
Description
Here is a chat transcript for the record
felixge/node-stack-trace
index.js
to native typescript
Here is the provided JavaScript code converted to TypeScript:
TypeScript
interface IParsedCallSite {
fileName: string | null;felixge/node-stack-trace
index.js
to native typescript
Here is the provided JavaScript code converted to TypeScript:
TypeScript
interface IParsedCallSite {
fileName: string | null;
lineNumber: number | null;
functionName: string | null;
typeName: string | null;
methodName: string | null;
columnNumber: number | null;
native: boolean | null;
}
export function get(belowFn?: Function): NodeJS.CallSite[] {
const oldLimit = Error.stackTraceLimit;
Error.stackTraceLimit = Infinity;
const dummyObject = {};
const v8Handler = Error.prepareStackTrace;
Error.prepareStackTrace = function(dummyObject, v8StackTrace: NodeJS.CallSite[]) {
return v8StackTrace;
};
Error.captureStackTrace(dummyObject, belowFn || get);
const v8StackTrace = (dummyObject as any).stack;
Error.prepareStackTrace = v8Handler;
Error.stackTraceLimit = oldLimit;
return v8StackTrace;
}
export function parse(err: Error): IParsedCallSite[] {
if (!err.stack) {
return [];
}
const lines = err.stack.split('\n').slice(1);
return lines
.map((line) => {
if (line.match(/^\s*[-]{4,}$/)) {
return createParsedCallSite({
fileName: line,
lineNumber: null,
functionName: null,
typeName: null,
methodName: null,
columnNumber: null,
native: null,
});
}
const lineMatch = line.match(/at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/);
if (!lineMatch) {
return;
}
let object: string | null = null;
let method: string | null = null;
let functionName: string | null = null;
let typeName: string | null = null;
let methodName: string | null = null;
const isNative = (lineMatch[5] === 'native');
if (lineMatch[1]) {
functionName = lineMatch[1];
let methodStart = functionName.lastIndexOf('.');
if (functionName[methodStart - 1] === '.') {
methodStart--;
}
if (methodStart > 0) {
object = functionName.substr(0, methodStart);
method = functionName.substr(methodStart + 1);
const objectEnd = object.indexOf('.Module');
if (objectEnd > 0) {
functionName = functionName.substr(objectEnd + 1);
object = object.substr(0, objectEnd);
}
}
}
if (method) {
typeName = object;
methodName = method;
}
if (method === '<anonymous>') {
methodName = null;
functionName = null;
}
const properties: IParsedCallSite = {
fileName: lineMatch[2] || null,
lineNumber: parseInt(lineMatch[3], 10) || null,
functionName: functionName,
typeName: typeName,
methodName: methodName,
columnNumber: parseInt(lineMatch[4], 10) || null,
native: isNative,
};
return createParsedCallSite(properties);
})
.filter((callSite): callSite is IParsedCallSite => !!callSite);
}
class CallSite implements IParsedCallSite {
fileName: string | null;
lineNumber: number | null;
functionName: string | null;
typeName: string | null;
methodName: string | null;
columnNumber: number | null;
native: boolean | null;
constructor(properties: IParsedCallSite) {
for (const property in properties) {
this[property] = properties[property];
}
}
getThis(): string | null {
return null;
}
getTypeName(): string | null {
return this.typeName;
}
getFunctionName(): string | null {
return this.functionName;
}
getMethodName(): string | null {
return this.methodName;
}
getFileName(): string | null {
return this.fileName;
}
getLineNumber(): number | null {
return this.lineNumber;
}
getColumnNumber(): number | null {
return this.columnNumber;
}
getFunction(): Function | null {
return null;
}
getEvalOrigin(): string | null {
return null;
}
isTopLevel(): boolean {
return false;
}
isEval(): boolean {
return false;
}
isNative(): boolean {
return this.native || false;
}
isConstructor(): boolean {
return false;
}
}
function createParsedCallSite(properties: IParsedCallSite): CallSite {
return new CallSite(properties);
}
This conversion includes the TypeScript interfaces and type annotations to ensure type safety.
now wrap in zod
To wrap the TypeScript code in Zod for validation, we first need to install the Zod library. If you haven't already, you can install it using npm:
sh
npm install zod
Next, we will update the TypeScript code to include Zod schemas for validation. Here is the updated code:
TypeScript
import { z } from 'zod';
// Define the schema for IParsedCallSite
const ParsedCallSiteSchema = z.object({
fileName: z.string().nullable(),
lineNumber: z.number().nullable(),
functionName: z.string().nullable(),
typeName: z.string().nullable(),
methodName: z.string().nullable(),
columnNumber: z.number().nullable(),
native: z.boolean().nullable(),
});
type IParsedCallSite = z.infer;
export function get(belowFn?: Function): NodeJS.CallSite[] {
const oldLimit = Error.stackTraceLimit;
Error.stackTraceLimit = Infinity;
const dummyObject = {};
const v8Handler = Error.prepareStackTrace;
Error.prepareStackTrace = function(dummyObject, v8StackTrace: NodeJS.CallSite[]) {
return v8StackTrace;
};
Error.captureStackTrace(dummyObject, belowFn || get);
const v8StackTrace = (dummyObject as any).stack;
Error.prepareStackTrace = v8Handler;
Error.stackTraceLimit = oldLimit;
return v8StackTrace;
}
export function parse(err: Error): IParsedCallSite[] {
if (!err.stack) {
return [];
}
const lines = err.stack.split('\n').slice(1);
return lines
.map((line) => {
if (line.match(/^\s*[-]{4,}$/)) {
return createParsedCallSite({
fileName: line,
lineNumber: null,
functionName: null,
typeName: null,
methodName: null,
columnNumber: null,
native: null,
});
}
const lineMatch = line.match(/at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/);
if (!lineMatch) {
return;
}
let object: string | null = null;
let method: string | null = null;
let functionName: string | null = null;
let typeName: string | null = null;
let methodName: string | null = null;
const isNative = (lineMatch[5] === 'native');
if (lineMatch[1]) {
functionName = lineMatch[1];
let methodStart = functionName.lastIndexOf('.');
if (functionName[methodStart - 1] === '.') {
methodStart--;
}
if (methodStart > 0) {
object = functionName.substr(0, methodStart);
method = functionName.substr(methodStart + 1);
const objectEnd = object.indexOf('.Module');
if (objectEnd > 0) {
functionName = functionName.substr(objectEnd + 1);
object = object.substr(0, objectEnd);
}
}
}
if (method) {
typeName = object;
methodName = method;
}
if (method === '<anonymous>') {
methodName = null;
functionName = null;
}
const properties: IParsedCallSite = {
fileName: lineMatch[2] || null,
lineNumber: parseInt(lineMatch[3], 10) || null,
functionName: functionName,
typeName: typeName,
methodName: methodName,
columnNumber: parseInt(lineMatch[4], 10) || null,
native: isNative,
};
// Validate the properties using Zod schema
ParsedCallSiteSchema.parse(properties);
return createParsedCallSite(properties);
})
.filter((callSite): callSite is IParsedCallSite => !!callSite);
}
class CallSite implements IParsedCallSite {
fileName: string | null;
lineNumber: number | null;
functionName: string | null;
typeName: string | null;
methodName: string | null;
columnNumber: number | null;
native: boolean | null;
constructor(properties: IParsedCallSite) {
for (const property in properties) {
this[property] = properties[property];
}
}
getThis(): string | null {
return null;
}
getTypeName(): string | null {
return this.typeName;
}
getFunctionName(): string | null {
return this.functionName;
}
getMethodName(): string | null {
return this.methodName;
}
getFileName(): string | null {
return this.fileName;
}
getLineNumber(): number | null {
return this.lineNumber;
}
getColumnNumber(): number | null {
return this.columnNumber;
}
getFunction(): Function | null {
return null;
}
getEvalOrigin(): string | null {
return null;
}
isTopLevel(): boolean {
return false;
}
isEval(): boolean {
return false;
}
isNative(): boolean {
return this.native || false;
}
isConstructor(): boolean {
return false;
}
}
function createParsedCallSite(properties: IParsedCallSite): CallSite {
return new CallSite(properties);
}
This code adds the Zod library to validate the IParsedCallSite interface. The ParsedCallSiteSchema schema is used to validate the properties of each parsed call site.
lineNumber: number | null;
functionName: string | null;
typeName: string | null;
methodName: string | null;
columnNumber: number | null;
native: boolean | null;
}
export function get(belowFn?: Function): NodeJS.CallSite[] {
const oldLimit = Error.stackTraceLimit;
Error.stackTraceLimit = Infinity;
const dummyObject = {};
const v8Handler = Error.prepareStackTrace;
Error.prepareStackTrace = function(dummyObject, v8StackTrace: NodeJS.CallSite[]) {
return v8StackTrace;
};
Error.captureStackTrace(dummyObject, belowFn || get);
const v8StackTrace = (dummyObject as any).stack;
Error.prepareStackTrace = v8Handler;
Error.stackTraceLimit = oldLimit;
return v8StackTrace;
}
export function parse(err: Error): IParsedCallSite[] {
if (!err.stack) {
return [];
}
const lines = err.stack.split('\n').slice(1);
return lines
.map((line) => {
if (line.match(/^\s*[-]{4,}$/)) {
return createParsedCallSite({
fileName: line,
lineNumber: null,
functionName: null,
typeName: null,
methodName: null,
columnNumber: null,
native: null,
});
}
const lineMatch = line.match(/at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/);
if (!lineMatch) {
return;
}
let object: string | null = null;
let method: string | null = null;
let functionName: string | null = null;
let typeName: string | null = null;
let methodName: string | null = null;
const isNative = (lineMatch[5] === 'native');
if (lineMatch[1]) {
functionName = lineMatch[1];
let methodStart = functionName.lastIndexOf('.');
if (functionName[methodStart - 1] === '.') {
methodStart--;
}
if (methodStart > 0) {
object = functionName.substr(0, methodStart);
method = functionName.substr(methodStart + 1);
const objectEnd = object.indexOf('.Module');
if (objectEnd > 0) {
functionName = functionName.substr(objectEnd + 1);
object = object.substr(0, objectEnd);
}
}
}
if (method) {
typeName = object;
methodName = method;
}
if (method === '<anonymous>') {
methodName = null;
functionName = null;
}
const properties: IParsedCallSite = {
fileName: lineMatch[2] || null,
lineNumber: parseInt(lineMatch[3], 10) || null,
functionName: functionName,
typeName: typeName,
methodName: methodName,
columnNumber: parseInt(lineMatch[4], 10) || null,
native: isNative,
};
return createParsedCallSite(properties);
})
.filter((callSite): callSite is IParsedCallSite => !!callSite);
}
class CallSite implements IParsedCallSite {
fileName: string | null;
lineNumber: number | null;
functionName: string | null;
typeName: string | null;
methodName: string | null;
columnNumber: number | null;
native: boolean | null;
constructor(properties: IParsedCallSite) {
for (const property in properties) {
this[property] = properties[property];
}
}
getThis(): string | null {
return null;
}
getTypeName(): string | null {
return this.typeName;
}
getFunctionName(): string | null {
return this.functionName;
}
getMethodName(): string | null {
return this.methodName;
}
getFileName(): string | null {
return this.fileName;
}
getLineNumber(): number | null {
return this.lineNumber;
}
getColumnNumber(): number | null {
return this.columnNumber;
}
getFunction(): Function | null {
return null;
}
getEvalOrigin(): string | null {
return null;
}
isTopLevel(): boolean {
return false;
}
isEval(): boolean {
return false;
}
isNative(): boolean {
return this.native || false;
}
isConstructor(): boolean {
return false;
}
}
function createParsedCallSite(properties: IParsedCallSite): CallSite {
return new CallSite(properties);
}
This conversion includes the TypeScript interfaces and type annotations to ensure type safety.
now wrap in zod
To wrap the TypeScript code in Zod for validation, we first need to install the Zod library. If you haven't already, you can install it using npm:
sh
npm install zod
Next, we will update the TypeScript code to include Zod schemas for validation. Here is the updated code:
TypeScript
import { z } from 'zod';
// Define the schema for IParsedCallSite
const ParsedCallSiteSchema = z.object({
fileName: z.string().nullable(),
lineNumber: z.number().nullable(),
functionName: z.string().nullable(),
typeName: z.string().nullable(),
methodName: z.string().nullable(),
columnNumber: z.number().nullable(),
native: z.boolean().nullable(),
});
type IParsedCallSite = z.infer;
export function get(belowFn?: Function): NodeJS.CallSite[] {
const oldLimit = Error.stackTraceLimit;
Error.stackTraceLimit = Infinity;
const dummyObject = {};
const v8Handler = Error.prepareStackTrace;
Error.prepareStackTrace = function(dummyObject, v8StackTrace: NodeJS.CallSite[]) {
return v8StackTrace;
};
Error.captureStackTrace(dummyObject, belowFn || get);
const v8StackTrace = (dummyObject as any).stack;
Error.prepareStackTrace = v8Handler;
Error.stackTraceLimit = oldLimit;
return v8StackTrace;
}
export function parse(err: Error): IParsedCallSite[] {
if (!err.stack) {
return [];
}
const lines = err.stack.split('\n').slice(1);
return lines
.map((line) => {
if (line.match(/^\s*[-]{4,}$/)) {
return createParsedCallSite({
fileName: line,
lineNumber: null,
functionName: null,
typeName: null,
methodName: null,
columnNumber: null,
native: null,
});
}
const lineMatch = line.match(/at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/);
if (!lineMatch) {
return;
}
let object: string | null = null;
let method: string | null = null;
let functionName: string | null = null;
let typeName: string | null = null;
let methodName: string | null = null;
const isNative = (lineMatch[5] === 'native');
if (lineMatch[1]) {
functionName = lineMatch[1];
let methodStart = functionName.lastIndexOf('.');
if (functionName[methodStart - 1] === '.') {
methodStart--;
}
if (methodStart > 0) {
object = functionName.substr(0, methodStart);
method = functionName.substr(methodStart + 1);
const objectEnd = object.indexOf('.Module');
if (objectEnd > 0) {
functionName = functionName.substr(objectEnd + 1);
object = object.substr(0, objectEnd);
}
}
}
if (method) {
typeName = object;
methodName = method;
}
if (method === '<anonymous>') {
methodName = null;
functionName = null;
}
const properties: IParsedCallSite = {
fileName: lineMatch[2] || null,
lineNumber: parseInt(lineMatch[3], 10) || null,
functionName: functionName,
typeName: typeName,
methodName: methodName,
columnNumber: parseInt(lineMatch[4], 10) || null,
native: isNative,
};
// Validate the properties using Zod schema
ParsedCallSiteSchema.parse(properties);
return createParsedCallSite(properties);
})
.filter((callSite): callSite is IParsedCallSite => !!callSite);
}
class CallSite implements IParsedCallSite {
fileName: string | null;
lineNumber: number | null;
functionName: string | null;
typeName: string | null;
methodName: string | null;
columnNumber: number | null;
native: boolean | null;
constructor(properties: IParsedCallSite) {
for (const property in properties) {
this[property] = properties[property];
}
}
getThis(): string | null {
return null;
}
getTypeName(): string | null {
return this.typeName;
}
getFunctionName(): string | null {
return this.functionName;
}
getMethodName(): string | null {
return this.methodName;
}
getFileName(): string | null {
return this.fileName;
}
getLineNumber(): number | null {
return this.lineNumber;
}
getColumnNumber(): number | null {
return this.columnNumber;
}
getFunction(): Function | null {
return null;
}
getEvalOrigin(): string | null {
return null;
}
isTopLevel(): boolean {
return false;
}
isEval(): boolean {
return false;
}
isNative(): boolean {
return this.native || false;
}
isConstructor(): boolean {
return false;
}
}
function createParsedCallSite(properties: IParsedCallSite): CallSite {
return new CallSite(properties);
}
This code adds the Zod library to validate the IParsedCallSite interface. The ParsedCallSiteSchema schema is used to validate the properties of each parsed call site.