Skip to content

Commit

Permalink
Add Quote Rule to ESLint (#20)
Browse files Browse the repository at this point in the history
* Add Quote Rule to ESLint
 Lint __tests__
 Fixes #13

* Add JSDoc Rule to ESLint (#21)

Fixes #12
  • Loading branch information
bobbyg603 authored Apr 20, 2021
1 parent 41c9c0a commit beb1c37
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 74 deletions.
1 change: 0 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ coverage
.eslintrc.js
babel.config.js
jest.config.js
__tests__
.idea
29 changes: 28 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,40 @@ module.exports = {
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint',
'jsdoc'
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
rules: {
'semi': ['error', 'always'],
'object-curly-spacing': ['error', 'always']
'object-curly-spacing': ['error', 'always'],
'quotes': ['error', 'single'],
'jsdoc/check-access': 1,
'jsdoc/check-alignment': 1,
'jsdoc/check-param-names': 1,
'jsdoc/check-property-names': 1,
'jsdoc/check-tag-names': 1,
'jsdoc/check-types': 1,
'jsdoc/check-values': 1,
'jsdoc/empty-tags': 1,
'jsdoc/implements-on-classes': 1,
'jsdoc/newline-after-description': 1,
'jsdoc/no-undefined-types': 1,
'jsdoc/require-jsdoc': 1,
'jsdoc/require-param': 1,
'jsdoc/require-param-description': 1,
'jsdoc/require-param-name': 1,
'jsdoc/require-property': 1,
'jsdoc/require-property-description': 1,
'jsdoc/require-property-name': 1,
'jsdoc/require-property-type': 1,
'jsdoc/require-returns': 1,
'jsdoc/require-returns-check': 1,
'jsdoc/require-returns-description': 1,
'jsdoc/require-yields': 1,
'jsdoc/require-yields-check': 1,
'jsdoc/valid-types': 1
}
};
76 changes: 38 additions & 38 deletions __tests__/stack-converter.test.ts
Original file line number Diff line number Diff line change
@@ -1,84 +1,84 @@
import * as fs from "fs";
import * as path from "path";
import { StackConverter } from "../lib/stack-converter";
import * as fs from 'fs';
import * as path from 'path';
import { StackConverter } from '../lib/stack-converter';

const TESTING_DIR = "__tests__";
const TESTING_DATA_DIR = path.join(TESTING_DIR, "test-data");
const TESTING_DIR = '__tests__';
const TESTING_DATA_DIR = path.join(TESTING_DIR, 'test-data');

const readStack = (file: string): string => {
return fs.readFileSync(file, {
encoding: "utf8",
flag: "r",
encoding: 'utf8',
flag: 'r',
});
};

describe("StackConverter", () => {
describe("constructor", () => {
test("throws if no sourceMapFilePaths were provided", () => {
describe('StackConverter', () => {
describe('constructor', () => {
test('throws if no sourceMapFilePaths were provided', () => {
expect(() => new StackConverter([])).toThrow(/Could not create StackConverter: no source map file paths were provided!/);
});
});

describe("createFromDirectory", () => {
test("throws if no sourceMapFilePaths were provided", async () => {
describe('createFromDirectory', () => {
test('throws if no sourceMapFilePaths were provided', async () => {
await expect(
async () => {
const baseFile = "dir-exists-no-map-files";
const baseFile = 'dir-exists-no-map-files';
const mapFilePath = path.join(TESTING_DATA_DIR, baseFile);
await StackConverter.createFromDirectory(mapFilePath);
}
).rejects.toThrow(/Could not create StackConverter: no source map file paths were provided!/);
});

test("throws if directory does not exist at provided path", async () => {
test('throws if directory does not exist at provided path', async () => {
await expect(
async () => {
await StackConverter.createFromDirectory("does-not-exist");
await StackConverter.createFromDirectory('does-not-exist');
}
).rejects.toThrow(/Could not create StackConverter: does-not-exist does not exist or is inaccessible/);
});
});

describe("convert", () => {
test("empty stack results in empty results but no error", async () => {
const mapFile = path.join(TESTING_DATA_DIR, "stack-1.js.map");
describe('convert', () => {
test('empty stack results in empty results but no error', async () => {
const mapFile = path.join(TESTING_DATA_DIR, 'stack-1.js.map');
const stackConverter = new StackConverter([mapFile]);
const { error, stack } = await stackConverter.convert("");
const { error, stack } = await stackConverter.convert('');
expect(error).toBeUndefined();
expect(stack).toMatchInlineSnapshot(`""`);
expect(stack).toMatchInlineSnapshot('""');
});

test("source map file that does not exist results stack frame with error message", async () => {
const missingJsFileName = "does-not-exist.js";
const missingJsMapFileName = `${missingJsFileName}.map`
test('source map file that does not exist results stack frame with error message', async () => {
const missingJsFileName = 'does-not-exist.js';
const missingJsMapFileName = `${missingJsFileName}.map`;
const missingJsMapPath = path.join(TESTING_DATA_DIR, missingJsMapFileName);
const stackConverter = new StackConverter([missingJsMapPath]);
const { error, stack } = await stackConverter.convert(` at hello (${missingJsFileName}:1:1337)`);
expect(error).toBeFalsy();
expect(stack).toMatch(new RegExp(`Error loading source map for frame \\(file .*${missingJsMapFileName} does not exist or is inaccessible\\)`));
});

test("empty source map file results stack frame with error message", async () => {
const emptyJsFileName = "empty.js";
const emptyJsMapFileName = `${emptyJsFileName}.map`
test('empty source map file results stack frame with error message', async () => {
const emptyJsFileName = 'empty.js';
const emptyJsMapFileName = `${emptyJsFileName}.map`;
const emptyJsMapPath = path.join(TESTING_DATA_DIR, emptyJsMapFileName);
const stackConverter = new StackConverter([emptyJsMapPath]);
const { error, stack } = await stackConverter.convert(` at hello (${emptyJsFileName}:1:1337)`);
expect(error).toBeFalsy();
expect(stack).toMatch(new RegExp(`Error loading source map for frame \\(file .*${emptyJsMapFileName} was empty\\)`));
});

test("source map file that can't be parsed results stack frame with error message", async () => {
const stackFrameFileName = "corrupt.js";
test('source map file that can\'t be parsed results stack frame with error message', async () => {
const stackFrameFileName = 'corrupt.js';
const emptyJsMapPath = path.join(TESTING_DATA_DIR, `${stackFrameFileName}.map`);
const stackConverter = new StackConverter([emptyJsMapPath]);
const { error, stack } = await stackConverter.convert(` at hello (${stackFrameFileName}:1:1337)`);
expect(error).toBeFalsy();
expect(stack).toMatch(/Error loading source map for frame \(could not parse source map\)/);
});

test("read in stack-1 map file and convert stack-1 sample data", async () => {
const baseFile = "stack-1";
test('read in stack-1 map file and convert stack-1 sample data', async () => {
const baseFile = 'stack-1';
const mapFilePath = path.join(TESTING_DATA_DIR, `${baseFile}.js.map`);
const stackConverter = new StackConverter([mapFilePath]);
const stackFilePath = path.join(TESTING_DATA_DIR, `${baseFile}.txt`);
Expand All @@ -100,13 +100,13 @@ describe("StackConverter", () => {
`);
});

test("read in stack trace containing frames from multiple files missing source maps converts stack with errors", async () => {
const stackAndSourceMapDir = path.join(TESTING_DATA_DIR, "dir-multiple-source-map-files");
test('read in stack trace containing frames from multiple files missing source maps converts stack with errors', async () => {
const stackAndSourceMapDir = path.join(TESTING_DATA_DIR, 'dir-multiple-source-map-files');
const stackConverter = new StackConverter([
path.join(stackAndSourceMapDir, "main-es2015.cd6a577558c44d1be6da.js.map"),
path.join(stackAndSourceMapDir, "polyfills-es2015.2846539e99aef31c99d5.js.map")
path.join(stackAndSourceMapDir, 'main-es2015.cd6a577558c44d1be6da.js.map'),
path.join(stackAndSourceMapDir, 'polyfills-es2015.2846539e99aef31c99d5.js.map')
]);
const stackFile = path.join(stackAndSourceMapDir, "stack-to-convert.txt");
const stackFile = path.join(stackAndSourceMapDir, 'stack-to-convert.txt');
const stackText = readStack(stackFile);
const { error, stack } = await stackConverter.convert(stackText);
expect(error).toBeUndefined();
Expand All @@ -126,10 +126,10 @@ describe("StackConverter", () => {
`);
});

test("read in stack trace containing frames from multiple files and convert without errors", async () => {
const stackAndSourceMapDir = path.join(TESTING_DATA_DIR, "dir-multiple-source-map-files");
test('read in stack trace containing frames from multiple files and convert without errors', async () => {
const stackAndSourceMapDir = path.join(TESTING_DATA_DIR, 'dir-multiple-source-map-files');
const stackConverter = await StackConverter.createFromDirectory(stackAndSourceMapDir);
const stackFile = path.join(stackAndSourceMapDir, "stack-to-convert.txt");
const stackFile = path.join(stackAndSourceMapDir, 'stack-to-convert.txt');
const stackText = readStack(stackFile);
const { error, stack } = await stackConverter.convert(stackText);
expect(error).toBeUndefined();
Expand Down
51 changes: 25 additions & 26 deletions bin/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
import * as clipboardy from "clipboardy";
import { Stats } from "fs";
import * as fs from "fs/promises";
import { StackConverter } from "../lib/stack-converter";
import * as clipboardy from 'clipboardy';
import { Stats } from 'fs';
import * as fs from 'fs/promises';
import { StackConverter } from '../lib/stack-converter';

const helpAndExit = () => {
const help = `
@bugsplat/stack-converter contains a command line utility and set of libraries to help you demangle JavaScript stack frames.
stack-converter command line usage:
stack-converter [ [ "/source-map-directory" OR "/source.map.js" ] [ "/stack-trace.txt" ] ]
* Optionally provide either a path to a directory containing source maps or a .map.js file - Defaults to current directory
* Optionally provide a path to a .txt file containing a JavaScript Error stack trace - Defaults to value in clipboard
❤️ [email protected]
`;

console.log(help);
process.exit(1);
};

(async () => {
try {
Expand All @@ -16,12 +34,12 @@ import { StackConverter } from "../lib/stack-converter";

let sourceMapPath = process.argv[2];
if (!sourceMapPath) {
sourceMapPath = ".";
sourceMapPath = '.';
}

let sourceMapStat: Stats;
try {
sourceMapStat = await fs.lstat(sourceMapPath)
sourceMapStat = await fs.lstat(sourceMapPath);
} catch {
throw new Error(`Source map path ${sourceMapPath} does not exist`);
}
Expand All @@ -32,7 +50,7 @@ import { StackConverter } from "../lib/stack-converter";
stackFileContents = await clipboardy.read();
} else {
try {
await fs.lstat(stackFilePath)
await fs.lstat(stackFilePath);
} catch {
throw new Error(`Stack file path ${stackFilePath} does not exist`);
}
Expand All @@ -58,22 +76,3 @@ import { StackConverter } from "../lib/stack-converter";
process.exit(1);
}
})();


function helpAndExit() {
const help = `
@bugsplat/stack-converter contains a command line utility and set of libraries to help you demangle JavaScript stack frames.
stack-converter command line usage:
stack-converter [ [ "/source-map-directory" OR "/source.map.js" ] [ "/stack-trace.txt" ] ]
* Optionally provide either a path to a directory containing source maps or a .map.js file - Defaults to current directory
* Optionally provide a path to a .txt file containing a JavaScript Error stack trace - Defaults to value in clipboard
❤️ [email protected]
`;

console.log(help);
process.exit(1);
}
12 changes: 8 additions & 4 deletions lib/stack-converter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as fs from "fs/promises";
import * as fs from 'fs/promises';
import { get, set } from 'lodash';
import * as path from "path";
import * as path from 'path';
import { SourceMapConsumer } from 'source-map';
import * as stackTraceParser from 'stacktrace-parser';

Expand All @@ -16,18 +16,21 @@ export class StackConverter {

/**
* Create a StackConverter by passing an array of paths to source map files
*
* @param sourceMapFilePaths - an array of paths to source map files for converting stacks
* @throws - throws if no sourceMapFilePaths are provided
*/
constructor(private sourceMapFilePaths: Array<string>) {
if (!sourceMapFilePaths?.length) {
throw new Error(`Could not create StackConverter: no source map file paths were provided!`);
throw new Error('Could not create StackConverter: no source map file paths were provided!');
}
}

/**
* Convenience method for creating a StackConverter from a directory containing source map files
*
* @param dir - path to directory containing source map files
* @throws - throws if no source map files exist in dir
* @returns - promise that resolves to a new StackConverter
*/
static async createFromDirectory(dir: string): Promise<StackConverter> {
Expand All @@ -46,6 +49,7 @@ export class StackConverter {

/**
* Converts the file names and line numbers of a stack trace using the corresponding source maps
*
* @param stack - a string representation of a stack trace from a Error object
* @returns - promise that resolves to an object that contains an error or a stack
*/
Expand Down Expand Up @@ -163,7 +167,7 @@ export class StackConverter {
return { error: `file ${file} does not exist or is inaccessible` };
}

const fileData = await fs.readFile(file, { encoding: "utf8", flag: "r" });
const fileData = await fs.readFile(file, { encoding: 'utf8', flag: 'r' });
if (!fileData) {
return { error: `file ${file} was empty` };
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@typescript-eslint/parser": "^4.22.0",
"babel-jest": "^26.6.3",
"eslint": "^7.24.0",
"eslint-plugin-jsdoc": "^32.3.0",
"jest": "^26.6.3",
"ts-jest": "^26.5.4"
}
Expand Down
Loading

0 comments on commit beb1c37

Please sign in to comment.