Move from TsLint to EsLint

- Fix some error's but still not green (good enough for now)
This commit is contained in:
Johannes Zillmann 2024-03-20 09:07:48 -06:00
parent c696806a0e
commit 5bf4988da2
16 changed files with 2211 additions and 391 deletions

26
core/.eslintrc.js Normal file
View File

@ -0,0 +1,26 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
overrides: [
{
env: {
node: true,
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script',
},
},
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
rules: {},
};

2418
core/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@
"test-write": "jest --updateSnapshot test/Files.test.ts", "test-write": "jest --updateSnapshot test/Files.test.ts",
"build": "tsc", "build": "tsc",
"format": "prettier --write \"src/**/*.ts\"", "format": "prettier --write \"src/**/*.ts\"",
"lint": "tslint -p tsconfig.json", "lint": "eslint --ext .js,.ts src/** test/**",
"prepare": "npm run build", "prepare": "npm run build",
"prepublishOnly": "npm test && npm run lint", "prepublishOnly": "npm test && npm run lint",
"preversion": "npm run lint", "preversion": "npm run lint",
@ -33,14 +33,16 @@
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
"@typescript-eslint/eslint-plugin": "^7.3.1",
"@typescript-eslint/parser": "^7.3.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-file-snapshot": "^0.5.0", "jest-file-snapshot": "^0.5.0",
"patch-package": "^6.4.7", "patch-package": "^6.4.7",
"pdfjs-dist": "^2.5.207", "pdfjs-dist": "^2.5.207",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"ts-jest": "^29.1.2", "ts-jest": "^29.1.2",
"tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0",
"typescript": "^5.4.2" "typescript": "^5.4.2"
}, },
"dependencies": { "dependencies": {

View File

@ -113,26 +113,24 @@ const boldAndObliqueTypeFragments = [
't2bxti', 't2bxti',
]; ];
namespace FontType { export function declaredFontTypes(fontName: string): FontType[] {
export function declaredFontTypes(fontName: string): FontType[] { const fontNameLowerCase = fontName.toLowerCase();
const fontNameLowerCase = fontName.toLowerCase(); const boldAndOblique = boldAndObliqueTypeFragments.find((fragment) => fontNameLowerCase.includes(fragment));
const boldAndOblique = boldAndObliqueTypeFragments.find((fragment) => fontNameLowerCase.includes(fragment)); let bold: boolean;
let bold: boolean; let oblique: boolean;
let oblique: boolean; if (boldAndOblique) {
if (boldAndOblique) { bold = true;
bold = true; oblique = true;
oblique = true; } else {
} else { bold = !!boldTypeFragments.find((fragment) => fontNameLowerCase.includes(fragment));
bold = !!boldTypeFragments.find((fragment) => fontNameLowerCase.includes(fragment)); oblique = !!obliqueTypeFragments.find((fragment) => fontNameLowerCase.includes(fragment));
oblique = !!obliqueTypeFragments.find((fragment) => fontNameLowerCase.includes(fragment));
}
const fontTypes: FontType[] = [];
if (bold) {
fontTypes.push(FontType.BOLD);
}
if (oblique) {
fontTypes.push(FontType.OBLIQUE);
}
return fontTypes;
} }
const fontTypes: FontType[] = [];
if (bold) {
fontTypes.push(FontType.BOLD);
}
if (oblique) {
fontTypes.push(FontType.OBLIQUE);
}
return fontTypes;
} }

View File

@ -3,7 +3,7 @@ import { assertDefined, assertNot } from './assert';
import GlobalValue from './GlobalValue'; import GlobalValue from './GlobalValue';
export default class Globals { export default class Globals {
map: Map<string, any>; map: Map<string, unknown>;
constructor(globals?: Globals) { constructor(globals?: Globals) {
this.map = globals ? new Map(globals.map) : new Map(); this.map = globals ? new Map(globals.map) : new Map();
} }
@ -38,7 +38,7 @@ export default class Globals {
this.map.set(definition.key, value); this.map.set(definition.key, value);
} }
withValues(values: GlobalValue<any>[] | undefined): Globals { withValues(values: GlobalValue<unknown>[] | undefined): Globals {
values?.forEach((value) => { values?.forEach((value) => {
if (value.override) { if (value.override) {
this.override(value.definition, value.value); this.override(value.definition, value.value);

View File

@ -1,5 +1,4 @@
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { assertDefined } from './assert';
export default class Item { export default class Item {
page: number; page: number;

View File

@ -8,7 +8,7 @@ import ChangeIndex, {
Direction, Direction,
} from './ChangeIndex'; } from './ChangeIndex';
import Item from '../Item'; import Item from '../Item';
import { assertNot, assertDefined } from '../assert'; import { assertNot } from '../assert';
const ADDITION = new Addition(); const ADDITION = new Addition();
const REMOVAL = new Removal(); const REMOVAL = new Removal();

View File

@ -23,7 +23,7 @@ export default interface EvaluationIndex {
* @returns the score of the item in the context of the evaluation if there is any. * @returns the score of the item in the context of the evaluation if there is any.
* Think of it as an explanation for classification of an item. * Think of it as an explanation for classification of an item.
*/ */
evaluationScore(item: Item): any; evaluationScore(item: Item): unknown;
/** /**
* @returns true if the index tracked evaluation scores. * @returns true if the index tracked evaluation scores.

View File

@ -1,9 +1,8 @@
import { assertDefined } from '../assert';
import Item from '../Item'; import Item from '../Item';
import EvaluationIndex from './EvaluationIndex'; import EvaluationIndex from './EvaluationIndex';
export default class EvaluationTracker implements EvaluationIndex { export default class EvaluationTracker implements EvaluationIndex {
private evaluations: Map<string, any> = new Map(); private evaluations: Map<string, unknown> = new Map();
private scored = false; private scored = false;
evaluationCount() { evaluationCount() {
@ -22,7 +21,7 @@ export default class EvaluationTracker implements EvaluationIndex {
return this.evaluations.get(item.uuid); return this.evaluations.get(item.uuid);
} }
trackEvaluation(item: Item, score: any = undefined) { trackEvaluation(item: Item, score: unknown = undefined) {
if (typeof score !== 'undefined') { if (typeof score !== 'undefined') {
this.scored = true; this.scored = true;
} }

View File

@ -2,8 +2,8 @@ export function flatMap<T, S>(array: T[], func: (element: T, idx: number) => S[]
return array.reduce((result, entry, idx) => result.concat(func(entry, idx)), [] as S[]); return array.reduce((result, entry, idx) => result.concat(func(entry, idx)), [] as S[]);
} }
export function groupBy<T>(array: T[], groupKey: (element: T) => any): T[][] { export function groupBy<T, S>(array: T[], groupKey: (element: T) => S): T[][] {
const groupMap = array.reduce((map: Map<object, T[]>, element: T) => { const groupMap = array.reduce((map: Map<S, T[]>, element: T) => {
const key = groupKey(element); const key = groupKey(element);
const elementsInGroup = map.get(key); const elementsInGroup = map.get(key);
if (elementsInGroup) { if (elementsInGroup) {
@ -13,19 +13,20 @@ export function groupBy<T>(array: T[], groupKey: (element: T) => any): T[][] {
} }
return map; return map;
}, new Map()); }, new Map());
return Array.from(groupMap, ([key, value]) => value); // eslint-disable-next-line @typescript-eslint/no-unused-vars
return Array.from(groupMap, ([_, value]) => value);
} }
export function flatten<T>(array: T[][]): T[] { export function flatten<T>(array: T[][]): T[] {
return flatMap(array, (e) => e); return flatMap(array, (e) => e);
} }
export function arraysEqual(a: any[], b: any): boolean { export function arraysEqual<T>(a: T[], b: T[]): boolean {
if (a === b) return true; if (a === b) return true;
if (a == null || b == null) return false; if (a == null || b == null) return false;
if (a.length !== b.length) return false; if (a.length !== b.length) return false;
for (var i = 0; i < a.length; ++i) { for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false; if (a[i] !== b[i]) return false;
} }
return true; return true;

View File

@ -8,15 +8,15 @@ export function onlyUniques<T>(value: T, index: number, self: T[]) {
return self.indexOf(value) === index; return self.indexOf(value) === index;
} }
export function ascending<T>(a: number, b: number): number { export function ascending(a: number, b: number): number {
return a - b; return a - b;
} }
export function descending<T>(a: number, b: number): number { export function descending(a: number, b: number): number {
return b - a; return b - a;
} }
export function count<T, S>(array: T[], find: (entry: T) => boolean): number { export function count<T>(array: T[], find: (entry: T) => boolean): number {
return array.reduce((count, entry) => (find(entry) ? count + 1 : count), 0); return array.reduce((count, entry) => (find(entry) ? count + 1 : count), 0);
} }
@ -27,18 +27,18 @@ export function median(values: number[]) {
return a - b; return a - b;
}); });
var half = Math.floor(values.length / 2); const half = Math.floor(values.length / 2);
if (values.length % 2) return values[half]; if (values.length % 2) return values[half];
return (values[half - 1] + values[half]) / 2.0; return (values[half - 1] + values[half]) / 2.0;
} }
type KeyExtractor = (item: Item) => any; type KeyExtractor<O> = (item: Item) => O;
type PageItemTransformer = (page: number, items: Item[]) => Item[]; type PageItemTransformer = (page: number, items: Item[]) => Item[];
type LineItemTransformer = (page: number, line: number, items: Item[]) => Item[]; type LineItemTransformer = (page: number, line: number, items: Item[]) => Item[];
function groupBy(items: Item[], extractKey: KeyExtractor): Item[][] { function groupBy<O>(items: Item[], extractKey: KeyExtractor<O>): Item[][] {
return items.reduce((pageItems: Item[][], item: Item) => { return items.reduce((pageItems: Item[][], item: Item) => {
const lastPageItems = pageItems[pageItems.length - 1]; const lastPageItems = pageItems[pageItems.length - 1];
if (!lastPageItems || extractKey(item) !== extractKey(lastPageItems[0])) { if (!lastPageItems || extractKey(item) !== extractKey(lastPageItems[0])) {
@ -69,7 +69,7 @@ export function transformGroupedByPage(items: Item[], groupedTransformer: PageIt
} }
export function transformGroupedByPageAndLine(items: Item[], groupedTransformer: LineItemTransformer): Item[] { export function transformGroupedByPageAndLine(items: Item[], groupedTransformer: LineItemTransformer): Item[] {
let transformedItems: Item[] = []; const transformedItems: Item[] = [];
groupByPage(items).forEach((pageItems) => { groupByPage(items).forEach((pageItems) => {
groupByElement(pageItems, 'line').forEach((lineItems) => { groupByElement(pageItems, 'line').forEach((lineItems) => {
transformedItems.push(...groupedTransformer(pageItems[0].page, lineItems[0].data['line'], lineItems)); transformedItems.push(...groupedTransformer(pageItems[0].page, lineItems[0].data['line'], lineItems));

View File

@ -173,9 +173,9 @@ function parsePageMapping(
return typeof pageFactor === 'undefined' ? new PageMapping() : new PageMapping(pageFactor, true); return typeof pageFactor === 'undefined' ? new PageMapping() : new PageMapping(pageFactor, true);
} }
function getMostUsedKey(keyToOccurrence): any { function getMostUsedKey(keyToOccurrence: Record<string, number>): string {
var maxOccurence = 0; let maxOccurence = 0;
var maxKey: string | undefined; let maxKey: string = '';
Object.keys(keyToOccurrence).map((element) => { Object.keys(keyToOccurrence).map((element) => {
if (!maxKey || keyToOccurrence[element] > maxOccurence) { if (!maxKey || keyToOccurrence[element] > maxOccurence) {
maxOccurence = keyToOccurrence[element]; maxOccurence = keyToOccurrence[element];

View File

@ -19,9 +19,9 @@ import {
import ItemType from '../ItemType'; import ItemType from '../ItemType';
import { numbersAreConsecutive } from '../support/numberFunctions'; import { numbersAreConsecutive } from '../support/numberFunctions';
import TOC from '../TOC'; import TOC from '../TOC';
import FontType from '../FontType'; import FontType, { declaredFontTypes } from '../FontType';
import { flatten, groupBy } from '../support/functional'; import { flatten, groupBy } from '../support/functional';
import { getHeight, getText, getFontName, itemWithType, joinText } from '../support/items'; import { getHeight, getText, getFontName, itemWithType } from '../support/items';
const config = { const config = {
// How many characters a line with a ending number needs to have minimally to be a valid link // How many characters a line with a ending number needs to have minimally to be a valid link
@ -407,7 +407,7 @@ function fineMatchingHeadlineCanditate(
function hasHeadlineSymptoms(fontMap: Map<string, object>, mostUsedHeight: number, lineItems: Item[]): boolean { function hasHeadlineSymptoms(fontMap: Map<string, object>, mostUsedHeight: number, lineItems: Item[]): boolean {
return ( return (
getHeight(lineItems[0]) >= mostUsedHeight + config.minHeadlineDistance || getHeight(lineItems[0]) >= mostUsedHeight + config.minHeadlineDistance ||
FontType.declaredFontTypes(getFontName(fontMap, lineItems[0])).includes(FontType.BOLD) declaredFontTypes(getFontName(fontMap, lineItems[0])).includes(FontType.BOLD)
); );
} }

View File

@ -45,7 +45,7 @@ describe.each(files)('Test %p', (file) => {
const data = fs.readFileSync(`${folder}/${file}`); const data = fs.readFileSync(`${folder}/${file}`);
let debug: Debugger; let debug: Debugger;
let printedGlobals = new Set<string>(); const printedGlobals = new Set<string>();
beforeAll(async () => (debug = await pipeline.debug(data, () => {}))); beforeAll(async () => (debug = await pipeline.debug(data, () => {})));
test.each(transformers.map((t) => t.name).filter((name) => name !== 'Does nothing'))( test.each(transformers.map((t) => t.name).filter((name) => name !== 'Does nothing'))(
@ -97,7 +97,7 @@ describe('Selective transforms on URL PDFs', () => {
test.each(urls)('URL %p', async (url) => { test.each(urls)('URL %p', async (url) => {
const { fileName, data } = download(url); const { fileName, data } = download(url);
const debug = await pipeline.debug(data, () => {}); const debug = await pipeline.debug(data, () => {});
let printedGlobals = new Set<string>(); const printedGlobals = new Set<string>();
transformerNames.forEach((transformerName) => { transformerNames.forEach((transformerName) => {
const stageResult = debug.stageResult(debug.stageNames.indexOf(transformerName)); const stageResult = debug.stageResult(debug.stageNames.indexOf(transformerName));
@ -127,7 +127,7 @@ describe('Selective transforms on URL PDFs', () => {
}); });
function toHeader(stageResult: StageResult, alreadyPrintedGlobals: Set<string>): string { function toHeader(stageResult: StageResult, alreadyPrintedGlobals: Set<string>): string {
let groupedItemCount = stageResult const groupedItemCount = stageResult
.selectPages(false, true) .selectPages(false, true)
.reduce((itemCount, page) => itemCount + page.itemGroups.length, 0); .reduce((itemCount, page) => itemCount + page.itemGroups.length, 0);
@ -148,10 +148,10 @@ function toHeader(stageResult: StageResult, alreadyPrintedGlobals: Set<string>):
function globalsToString(globals: Globals, alreadyPrintedGlobals: Set<string>): object { function globalsToString(globals: Globals, alreadyPrintedGlobals: Set<string>): object {
return Array.from(globals.map) return Array.from(globals.map)
.filter(([key, value]) => !alreadyPrintedGlobals.has(key)) .filter(([key]) => !alreadyPrintedGlobals.has(key))
.reduce((obj, [key, value]) => { .reduce((obj, [key, value]) => {
if (key === TOC_GLOBAL.key) { if (key === TOC_GLOBAL.key) {
const toc: TOC = value; const toc: TOC = value as TOC;
value = { value = {
...toc, ...toc,
tocHeadlineItems: toc.tocHeadlineItems.map((item) => ({ tocHeadlineItems: toc.tocHeadlineItems.map((item) => ({

View File

@ -1,28 +1,28 @@
import FontType from 'src/FontType'; import FontType, { declaredFontTypes } from 'src/FontType';
test('descriptive names', async () => { test('descriptive names', async () => {
expect(FontType.declaredFontTypes('')).toEqual([]); expect(declaredFontTypes('')).toEqual([]);
expect(FontType.declaredFontTypes('JBRMKS+Helvetica')).toEqual([]); expect(declaredFontTypes('JBRMKS+Helvetica')).toEqual([]);
expect(FontType.declaredFontTypes('OMUGKQ+Helvetica-Bold')).toEqual([FontType.BOLD]); expect(declaredFontTypes('OMUGKQ+Helvetica-Bold')).toEqual([FontType.BOLD]);
expect(FontType.declaredFontTypes('SVUOCV+Helvetica-Oblique')).toEqual([FontType.OBLIQUE]); expect(declaredFontTypes('SVUOCV+Helvetica-Oblique')).toEqual([FontType.OBLIQUE]);
expect(FontType.declaredFontTypes('JUJONH+Helvetica-BoldOblique')).toEqual([FontType.BOLD, FontType.OBLIQUE]); expect(declaredFontTypes('JUJONH+Helvetica-BoldOblique')).toEqual([FontType.BOLD, FontType.OBLIQUE]);
}); });
// See http://mirrors.ibiblio.org/CTAN/systems/win32/bakoma/fonts/fonts.html // See http://mirrors.ibiblio.org/CTAN/systems/win32/bakoma/fonts/fonts.html
test('ATM Compatible Postscript Type 1', async () => { test('ATM Compatible Postscript Type 1', async () => {
expect(FontType.declaredFontTypes('')).toEqual([]); expect(declaredFontTypes('')).toEqual([]);
expect(FontType.declaredFontTypes('BBXMCN+CMR9')).toEqual([]); expect(declaredFontTypes('BBXMCN+CMR9')).toEqual([]);
expect(FontType.declaredFontTypes('EFUEQI+CMR10')).toEqual([]); expect(declaredFontTypes('EFUEQI+CMR10')).toEqual([]);
expect(FontType.declaredFontTypes('JZXNAL+CMCSC10')).toEqual([]); expect(declaredFontTypes('JZXNAL+CMCSC10')).toEqual([]);
expect(FontType.declaredFontTypes('ZYSMDY+CMBX10')).toEqual([FontType.BOLD]); expect(declaredFontTypes('ZYSMDY+CMBX10')).toEqual([FontType.BOLD]);
expect(FontType.declaredFontTypes('AENRCE+CMBX12')).toEqual([FontType.BOLD]); expect(declaredFontTypes('AENRCE+CMBX12')).toEqual([FontType.BOLD]);
expect(FontType.declaredFontTypes('HENPPA+BitstreamCyberbit-Roman')).toEqual([]); expect(declaredFontTypes('HENPPA+BitstreamCyberbit-Roman')).toEqual([]);
expect(FontType.declaredFontTypes('GHPDYG+CMSY10')).toEqual([]); expect(declaredFontTypes('GHPDYG+CMSY10')).toEqual([]);
expect(FontType.declaredFontTypes('VKLUIG+CMTT9')).toEqual([]); expect(declaredFontTypes('VKLUIG+CMTT9')).toEqual([]);
expect(FontType.declaredFontTypes('KSVJZ+CMTI10')).toEqual([FontType.OBLIQUE]); expect(declaredFontTypes('KSVJZ+CMTI10')).toEqual([FontType.OBLIQUE]);
expect(FontType.declaredFontTypes('QCQOVJ+CMTT10')).toEqual([]); expect(declaredFontTypes('QCQOVJ+CMTT10')).toEqual([]);
expect(FontType.declaredFontTypes('ASZLVZ+BitstreamCyberbit-Roman')).toEqual([]); expect(declaredFontTypes('ASZLVZ+BitstreamCyberbit-Roman')).toEqual([]);
expect(FontType.declaredFontTypes('KFYFQJ+CMMI10')).toEqual([FontType.OBLIQUE]); expect(declaredFontTypes('KFYFQJ+CMMI10')).toEqual([FontType.OBLIQUE]);
expect(FontType.declaredFontTypes('GYUWCJ+CMMIB10')).toEqual([FontType.BOLD, FontType.OBLIQUE]); expect(declaredFontTypes('GYUWCJ+CMMIB10')).toEqual([FontType.BOLD, FontType.OBLIQUE]);
expect(FontType.declaredFontTypes('OUVHFK+CMR8')).toEqual([]); expect(declaredFontTypes('OUVHFK+CMR8')).toEqual([]);
}); });

View File

@ -1,7 +0,0 @@
{
"extends": ["tslint:recommended", "tslint-config-prettier"],
"rules": {
"no-string-literal" : false,
"no-namespace" : false
}
}