Skip to content

Commit

Permalink
refactor!: update to cheminfo-types (#6)
Browse files Browse the repository at this point in the history
* refactor!: update to cheminfo-types

* fix: add peer-deps for eslint
  • Loading branch information
maasencioh committed Nov 5, 2021
1 parent caac9dc commit 12bf39a
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 69 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]

File parser for n-dimesional values.
File parser for n-dimensional values.

## Installation

Expand Down
27 changes: 18 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ndim-parser",
"version": "0.4.0",
"description": "File parser for n-dimesional values",
"description": "File parser for n-dimensional values",
"main": "./lib/index.js",
"module": "./lib-esm/index.js",
"types": "./lib/index.d.ts",
Expand All @@ -15,6 +15,7 @@
],
"scripts": {
"clean": "rimraf lib lib-esm",
"check-types": "tsc --noEmit",
"eslint": "eslint src --ext ts --cache",
"eslint-fix": "npm run eslint -- --fix",
"prepublishOnly": "npm run tsc",
Expand Down Expand Up @@ -44,14 +45,22 @@
"tabWidth": 2,
"trailingComma": "all"
},
"dependencies": {
"cheminfo-types": "^0.6.0"
},
"devDependencies": {
"@types/jest": "~26.0.15",
"eslint": "~7.14.0",
"eslint-config-cheminfo-typescript": "~8.0.5",
"jest": "~26.6.3",
"prettier": "~2.2.0",
"rimraf": "~3.0.2",
"ts-jest": "~26.4.4",
"typescript": "~4.1.2"
"@types/jest": "^27.0.2",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.1.0",
"eslint-config-cheminfo-typescript": "^10.2.2",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-jest": "^25.2.1",
"eslint-plugin-jsdoc": "^37.0.0",
"jest": "^27.3.1",
"prettier": "^2.4.1",
"rimraf": "^3.0.2",
"ts-jest": "^27.0.7",
"typescript": "^4.4.4"
}
}
16 changes: 8 additions & 8 deletions src/__tests__/appended.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ test('multiple breakdown', () => {
const parsed = appendedParser(csv);
expect(parsed).toHaveLength(164);
for (const serie of parsed) {
expect(serie.data).toHaveProperty('x');
expect(serie.data).toHaveProperty('y');
expect(serie.variables).toHaveProperty('x');
expect(serie.variables).toHaveProperty('y');
}
});

Expand All @@ -23,8 +23,8 @@ test('breakdown', () => {
);
const parsed = appendedParser(csv);
expect(parsed).toHaveLength(1);
expect(parsed[0].data).toHaveProperty('x');
expect(parsed[0].data).toHaveProperty('y');
expect(parsed[0].variables).toHaveProperty('x');
expect(parsed[0].variables).toHaveProperty('y');
});

test('capacitance', () => {
Expand All @@ -34,8 +34,8 @@ test('capacitance', () => {
);
const parsed = appendedParser(csv);
expect(parsed).toHaveLength(1);
expect(parsed[0].data).toHaveProperty('x');
expect(parsed[0].data).toHaveProperty('y');
expect(parsed[0].variables).toHaveProperty('x');
expect(parsed[0].variables).toHaveProperty('y');
});

test('IV', () => {
Expand All @@ -45,6 +45,6 @@ test('IV', () => {
);
const parsed = appendedParser(csv);
expect(parsed).toHaveLength(1);
expect(parsed[0].data).toHaveProperty('x');
expect(parsed[0].data).toHaveProperty('y');
expect(parsed[0].variables).toHaveProperty('x');
expect(parsed[0].variables).toHaveProperty('y');
});
10 changes: 5 additions & 5 deletions src/__tests__/general.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ temp, volt, curr, temp_sup

test('simpleExample', () => {
expect(ndParse(simpleExample)).toStrictEqual({
data: {
variables: {
x: { data: [1, 2, 3], label: 'temp' },
y: { data: [1, 2, 3], label: 'volt' },
c: { data: [1, 2, 3], label: 'curr' },
Expand All @@ -39,7 +39,7 @@ test('with options', () => {
],
}),
).toStrictEqual({
data: {
variables: {
x: { data: [1, 2, 3], label: 'ground volts' },
y: { data: [1, 2, 3], label: 'temperature' },
c: { data: [1, 2, 3], label: 'ground current' },
Expand All @@ -59,8 +59,8 @@ test('real file', () => {
);
const parsed = ndParse(csv);
const keys = ['x', 'y', 'G', 'Q', 'C', 'A', 'I', 'F', 'B'];
expect(parsed.meta['Channel.Mode']).toBe('V');
expect(Object.keys(parsed.data)).toStrictEqual(keys);
expect(parsed.meta?.['Channel.Mode']).toBe('V');
expect(Object.keys(parsed.variables)).toStrictEqual(keys);
});

test('breakdown', () => {
Expand All @@ -70,5 +70,5 @@ test('breakdown', () => {
);
const parsed = ndParse(csv, { isTagged: true });
const keys = ['x', 'y', 'I', 'A', 'B', 'C'];
expect(Object.keys(parsed.data)).toStrictEqual(keys);
expect(Object.keys(parsed.variables)).toStrictEqual(keys);
});
53 changes: 38 additions & 15 deletions src/appended.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { DataType, AppendedOptionsType, OutputType } from './types';
import type {
MeasurementXY,
MeasurementXYVariables,
OneLowerCase,
MeasurementVariable,
} from 'cheminfo-types';

import type { AppendedOptionsType } from './types';
import { isNumber, isNumericRow, orderedKeyMap } from './utils';

export function appendedParser(
text: string,
options: AppendedOptionsType = {},
): OutputType[] {
): MeasurementXY[] {
const { separator = ',', minNumericRows = 5 } = options;

const lines = text
Expand Down Expand Up @@ -49,7 +56,7 @@ export function appendedParser(
let headers: number[] = [];
let start: number[] = [0];
for (let i = 0; i < startNumeric.length; i++) {
// Last item in endNumec array
// Last item in array
if (i === startNumeric.length - 1) {
headers.push(startNumeric[i]);
}
Expand All @@ -65,18 +72,22 @@ export function appendedParser(
throw new Error('Unable to retrieve structure');
}
if (headers.length !== start.length) {
throw new Error('Unconsistent amount of headers an series');
throw new Error('Inconsistent amount of headers an series');
}

// If has tags ignore first row
const isTagged = !isNumber(lines[headers[0] + 1][0]);

// Split in metadata, header and data
let series = new Array(headers.length);
for (let serieIndex = 0; serieIndex < headers.length; serieIndex++) {
let series: MeasurementXY[] = new Array(headers.length);
for (let seriesIndex = 0; seriesIndex < headers.length; seriesIndex++) {
// Add metadata
let meta: Record<string, string> = {};
for (let index = start[serieIndex]; index < headers[serieIndex]; index++) {
for (
let index = start[seriesIndex];
index < headers[seriesIndex];
index++
) {
if (lines[index].length === 2) {
meta[lines[index][0]] = lines[index][1];
}
Expand All @@ -91,23 +102,35 @@ export function appendedParser(
}

// Add variables structure to add units
const labels = lines[headers[serieIndex]];
const labels = lines[headers[seriesIndex]];
const keys = orderedKeyMap(labels, isTagged);

// Add data
const endDataIndex =
serieIndex + 1 === headers.length
seriesIndex + 1 === headers.length
? lines.length - 1
: start[serieIndex + 1];
let data: Record<string, DataType> = {};
: start[seriesIndex + 1];
let variables: Partial<Record<OneLowerCase, MeasurementVariable>> = {};
for (let keyIndex = isTagged ? 1 : 0; keyIndex < keys.length; keyIndex++) {
data[keys[keyIndex]] = { data: [], label: labels[keyIndex] };
for (let index = headers[serieIndex] + 1; index < endDataIndex; index++) {
data[keys[keyIndex]].data.push(parseFloat(lines[index][keyIndex]));
let data: number[] = [];
for (
let index = headers[seriesIndex] + 1;
index < endDataIndex;
index++
) {
data.push(parseFloat(lines[index][keyIndex]));
}
variables[keys[keyIndex]] = { data, label: labels[keyIndex] };
}

if (!variables.x || !variables.y) {
throw new Error('x and y variables are necessary');
}

series[serieIndex] = { data, meta };
series[seriesIndex] = {
variables: variables as MeasurementXYVariables,
meta,
};
}

return series;
Expand Down
26 changes: 15 additions & 11 deletions src/general.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import type { GeneralOptionsType, OutputType } from './types';
import type { MeasurementXY, OneLowerCase } from 'cheminfo-types';

import type { GeneralOptionsType } from './types';
import { defaultKeyMapper, defaultLabelMap, intToChar } from './utils';

export function ndParse(
text: string,
options?: GeneralOptionsType,
): OutputType {
): MeasurementXY<number[]> {
const {
separator = ',',
isTagged = false,
keyMap = defaultKeyMapper,
labelMap = defaultLabelMap,
} = options || {};
let meta: OutputType['meta'] = {};
let data: OutputType['data'] = {};
let meta: MeasurementXY['meta'] = {};
let variables: Partial<MeasurementXY<number[]>['variables']> = {};

let tempHeader: string[] = [];
let header: string[] | undefined;
let header: OneLowerCase[] | undefined;
let labels: string[] = [];
let prevTag: string | undefined;
let tag: string | undefined;
Expand All @@ -30,7 +32,7 @@ export function ndParse(
const isNumeric =
line && (isTagged ? tag === 'DataValue' : !isNaN(Number(fields[0])));

// Checks if the header is setted
// Checks if the header is set
if (!header) {
// Classifies if it's a header
if (isNumeric) {
Expand All @@ -41,10 +43,10 @@ export function ndParse(
const label = labels[index] || intToChar(index);
const value = Number(fields[index]);
const key = header[index];
if (!isNaN(value)) data[key] = { data: [value], label };
if (!isNaN(value)) variables[key] = { data: [value], label };
}
} else {
// Add metavalues
// Add meta-values
if (tempHeader) {
const [key, ...values] = tempHeader.filter((t) => t);
if (
Expand All @@ -70,11 +72,13 @@ export function ndParse(
for (let index = 0; index < fields.length; index++) {
const key = header ? header[index] : intToChar(index);
const value = Number(fields[index]);
if (!isNaN(value)) data[key]?.data.push(value);
if (!isNaN(value)) variables[key]?.data.push(value);
}
}
}

const { x, y, ...unorderData } = data;
return { meta, data: { x, y, ...unorderData } };
const { x, y, ...unorderedData } = variables;
if (!x || !y) throw new Error('x and y variables are necessary');

return { meta, variables: { x, y, ...unorderedData } };
}
12 changes: 2 additions & 10 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
export interface DataType {
data: number[];
label: string;
}
import type { OneLowerCase } from 'cheminfo-types';

export interface AppendedOptionsType {
separator?: string;
minNumericRows?: number;
}

export interface OutputType {
meta: Record<string, string>;
data: Record<string, DataType>;
}

export interface GeneralOptionsType {
separator?: string;
isTagged?: boolean;
keyMap?: (keys: string[]) => string[];
keyMap?: (keys: string[]) => OneLowerCase[];
labelMap?: (keys: string[]) => string[];
}
26 changes: 16 additions & 10 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
export function intToChar(int: number): string {
return String.fromCharCode(65 + int);
import type { OneLowerCase } from 'cheminfo-types';

export function intToChar(int: number) {
return String.fromCharCode(65 + int) as OneLowerCase;
}

export function nextChar(keys: string[]): string {
export function nextChar(keys: string[]): OneLowerCase {
for (let int = 0; int < 52; int++) {
const char = intToChar(int);
if (!keys.includes(char)) return char;
}
throw new Error('To many variables for key mapper');
}

export function defaultKeyMapper(keys: string[]): string[] {
let currKeys: string[] = new Array(keys.length);
export function defaultKeyMapper(keys: string[]): OneLowerCase[] {
let currKeys: OneLowerCase[] = new Array(keys.length);
for (let index = 0; index < keys.length; index++) {
const key = keys[index];
if (index === 0) {
currKeys[index] = 'x';
} else if (index === 1) {
currKeys[index] = 'y';
} else {
currKeys[index] = !currKeys.includes(key[0])
? key[0]
const firstChar = key[0] as OneLowerCase;
currKeys[index] = !currKeys.includes(firstChar)
? firstChar
: nextChar(currKeys);
}
}
Expand All @@ -33,7 +36,7 @@ export function defaultLabelMap(keys: string[]): string[] {

export function isNumericRow(line: string[]): boolean {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_first, ...list] = line;
const [first, ...list] = line;
const filtered = list.filter((val) => !!val);
if (filtered.length === 0) return false;
return filtered.reduce((acc: boolean, curr) => acc && isNumber(curr), true);
Expand All @@ -43,8 +46,11 @@ export function isNumber(str: string): boolean {
return !isNaN(parseFloat(str));
}

export function orderedKeyMap(keys: string[], ignoreFirst: boolean): string[] {
let currKeys: string[] = new Array(keys.length);
export function orderedKeyMap(
keys: string[],
ignoreFirst: boolean,
): OneLowerCase[] {
let currKeys: OneLowerCase[] = new Array(keys.length);
const start = ignoreFirst ? 1 : 0;
for (let index = 0; index < keys.length; index++) {
if (index === start) {
Expand Down

0 comments on commit 12bf39a

Please sign in to comment.