Merge branch 'typescript'

This commit is contained in:
Nick Playfair 2021-03-18 00:58:51 +00:00
commit 43febed079
8 changed files with 1434 additions and 1063 deletions

2
.eslintignore Normal file
View File

@ -0,0 +1,2 @@
node_modules/
dist/

View File

@ -1,14 +1,16 @@
{ {
"env": { "root": true,
"browser": true, "parser": "@typescript-eslint/parser",
"commonjs": true, "plugins": [
"es2021": true "@typescript-eslint"
}, ],
"extends": [ "extends": [
"airbnb-base" "eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
], ],
"parserOptions": { "parserOptions": {
"ecmaVersion": 12 "project": "./tsconfig.json"
}, },
"rules": { "rules": {
"no-console": "off" "no-console": "off"

2046
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,10 +5,11 @@
"main": "bom2table.js", "main": "bom2table.js",
"scripts": { "scripts": {
"build": "npm run bundle && npm run copy:html && npm run copy:css", "build": "npm run bundle && npm run copy:html && npm run copy:css",
"bundle": "browserify ./src/bom2table.js -p tinyify -o ./dist/bundle.js", "bundle": "browserify ./src/bom2table.ts -p [ tsify --noImplicitAny ] -o ./dist/bundle.js",
"copy:html": "cpy 'src/*.html' 'dist/'", "copy:html": "cpy 'src/*.html' 'dist/'",
"copy:css": "cpy 'src/*.css' 'dist/'", "copy:css": "cpy 'src/*.css' 'dist/'",
"dev": "watchify ./src/bom2table.js -o ./dist/bundle.js -v" "dev": "watchify ./src/bom2table.js -o ./dist/bundle.js -v",
"lint": "eslint . --ext .ts"
}, },
"author": "nplayfair", "author": "nplayfair",
"license": "MIT", "license": "MIT",
@ -18,15 +19,17 @@
"pretty": "^2.0.0" "pretty": "^2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/csvtojson": "^1.1.5",
"@types/js-beautify": "^1.13.1",
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"browserify": "^17.0.0", "browserify": "^17.0.0",
"cpy-cli": "^3.1.1", "cpy-cli": "^3.1.1",
"eslint": "^7.21.0", "eslint": "^7.22.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-prettier": "^3.3.1",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"tinyify": "^3.0.0", "tinyify": "^3.0.0",
"tsify": "^5.0.2",
"typescript": "^4.2.3",
"watchify": "^4.0.0" "watchify": "^4.0.0"
} }
} }

View File

@ -1,166 +0,0 @@
/* eslint-disable array-callback-return */
// Modules
const beautify = require('js-beautify').html;
const csv = require('csvtojson');
// Configuration
// Which components should we remove from the BOM?
const rejectedParts = [
'TP1',
'TP2',
'TP3',
'G',
'U$1',
'S1',
'J1',
'J2',
'JP1',
'JP2',
'V',
'I',
'O',
'T1',
'T2',
'T3',
'INPUT',
];
// Return false if the Part value of the object passed in is in the list to remove
function isJunk(element) {
return !rejectedParts.includes(element.Part);
}
function getPartType(partName) {
// console.log(partName.Part);
if (partName.Part.match(/^C\d/) != null) {
return 'C';
// eslint-disable-next-line no-else-return
} else if (partName.Part.match(/^R\d/) != null) {
return 'R';
}
return 'Q';
}
function getJSONParts(allParts) {
const jsonParts = {};
const C = {};
const R = {};
const Q = {};
allParts.map((partEntry) => {
switch (getPartType(partEntry)) {
case 'C':
C[partEntry.Part] = partEntry.Value;
break;
case 'R':
R[partEntry.Part] = partEntry.Value;
break;
default:
Q[partEntry.Part] = partEntry.Value;
}
});
jsonParts.C = C;
jsonParts.R = R;
jsonParts.Q = Q;
return jsonParts;
}
// Format the HTML nicely and output to a pre code block
function displayMarkup() {
const tableCode = document.querySelector('table').outerHTML;
const markup = document.getElementById('markup');
markup.innerText = beautify(tableCode);
}
// Table functions
function clearTable() {
document.querySelector('table').innerHTML = '';
}
function generateTableHead(table, data) {
const thead = table.createTHead();
const row = thead.insertRow();
// Populate Header row
data.map((key) => {
const th = document.createElement('th');
const text = document.createTextNode(key);
th.appendChild(text);
row.appendChild(th);
});
}
function generateTableBody(table, data) {
data.map((component) => {
const row = table.insertRow();
// Insert Part Name
const partName = row.insertCell();
const partNameText = document.createTextNode(component.Part);
partName.appendChild(partNameText);
// Insert Part Value
const partVal = row.insertCell();
const partValText = document.createTextNode(component.Value);
partVal.appendChild(partValText);
});
}
function makeTable(csvString) {
csv({
delimiter: ';',
includeColumns: /(Part|Value)/,
ignoreEmpty: true,
})
.fromString(csvString)
.then((jsonObj) => {
// Create array containing only relevant parts
const parts = jsonObj.filter(isJunk);
console.log(parts);
const table = document.querySelector('table');
const headerData = Object.keys(parts[0]);
generateTableBody(table, parts);
generateTableHead(table, headerData);
displayMarkup();
})
.catch((e) => {
console.error(e);
});
}
// Create a JSON object for Contentful
function makeJSON(csvString) {
csv({
delimiter: ';',
includeColumns: /(Part|Value)/,
ignoreEmpty: true,
})
.fromString(csvString)
.then((res) => {
const object = res.filter(isJunk);
const parts = getJSONParts(object);
document.getElementById('jsonObject').innerText = JSON.stringify(
parts,
null,
2,
);
})
.catch((e) => {
console.error(e);
});
}
function handleFiles() {
const csvFilePath = this.files[0];
const reader = new FileReader();
reader.readAsText(csvFilePath);
reader.onload = () => {
clearTable();
makeTable(reader.result);
makeJSON(reader.result);
};
}
const csvPicker = document.getElementById('csvFile');
csvPicker.addEventListener('change', handleFiles, false);

160
src/bom2table.ts Normal file
View File

@ -0,0 +1,160 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
// Modules
import { html as beautify } from 'js-beautify';
import csv from 'csvtojson';
import { Converter } from 'csvtojson/v2/Converter';
// Configuration
// Which components should we remove from the BOM?
const rejectedParts = [
'TP1',
'TP2',
'TP3',
'G',
'U$1',
'S1',
'J1',
'J2',
'JP1',
'JP2',
'V',
'I',
'O',
'T1',
'T2',
'T3',
'INPUT',
];
// Return false if the Part value of the object passed in is in the list to remove
function isJunk(element: part) {
return !rejectedParts.includes(element.Part);
}
function getPartType(component: part) {
if (component.Part.match(/^C\d/) != null) {
return 'C';
} else if (component.Part.match(/^R\d/) != null) {
return 'R';
}
return 'Q';
}
function getJSONParts(allParts: part[]) {
const jsonParts: structuredParts = {
C: {},
R: {},
Q: {},
};
allParts.map((partEntry: part) => {
// Sort parts into capacitors, resistors and others
switch (getPartType(partEntry)) {
case 'C':
jsonParts.C[partEntry.Part] = partEntry.Value;
break;
case 'R':
jsonParts.R[partEntry.Part] = partEntry.Value;
break;
default:
jsonParts.Q[partEntry.Part] = partEntry.Value;
}
});
return jsonParts;
}
// Format the HTML nicely and output to a pre code block
function displayMarkup() {
const tableCode = document.querySelector('table')!.outerHTML;
const markup = document.getElementById('markup') as HTMLElement;
markup.innerText = beautify(tableCode);
}
// Table functions
function clearTable() {
document.querySelector('table')!.innerHTML = '';
}
function generateTableHead(table: HTMLTableElement, data: Array<string>) {
const thead = table.createTHead();
const row = thead.insertRow();
// Populate Header row
data.map((key) => {
const th = document.createElement('th');
const text = document.createTextNode(key);
th.appendChild(text);
row.appendChild(th);
});
}
function generateTableBody(table: HTMLTableElement, data: part[]) {
data.map((component) => {
const row = table.insertRow();
// Insert Part Name
const partName = row.insertCell();
const partNameText = document.createTextNode(component.Part);
partName.appendChild(partNameText);
// Insert Part Value
const partVal = row.insertCell();
const partValText = document.createTextNode(component.Value);
partVal.appendChild(partValText);
});
}
async function makeTable(csvString: string) {
const converter: Converter = csv({
delimiter: ';',
includeColumns: /(Part|Value)/,
ignoreEmpty: true,
})
const jsonArray = await converter.fromString(csvString);
// Filter out unwanted parts
const parts = jsonArray.filter(isJunk);
// Build table
const table = document.querySelector('table') as HTMLTableElement;
const headerData = Object.keys(parts[0]);
generateTableBody(table, parts);
generateTableHead(table, headerData);
displayMarkup();
}
// Create a JSON object for Contentful
function makeJSON(csvString: string) {
csv({
delimiter: ';',
includeColumns: /(Part|Value)/,
ignoreEmpty: true,
})
.fromString(csvString)
.then((res) => {
const object = res.filter(isJunk);
const parts = getJSONParts(object);
document.getElementById('jsonObject')!.innerText = JSON.stringify(
parts,
null,
2,
);
});
}
const csvPicker = document.getElementById('csvFile') as HTMLInputElement;
csvPicker.onchange = function handleFiles(event: Event) {
const target = event.target as HTMLInputElement;
const csvFile: File = (target.files as FileList)[0];
const reader = new FileReader();
reader.readAsText(csvFile);
reader.onload = () => {
if (reader.result == null) {
throw new Error('Something went wrong.');
}
const csvString = reader.result.toString();
clearTable();
makeTable(csvString);
makeJSON(csvString);
};
}

16
src/boms2table.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
interface part {
Part: string,
Value: string,
}
interface structuredParts {
C: {
[key: string]: string
},
R: {
[key: string]: string
},
Q: {
[key: string]: string
}
}

74
tsconfig.json Normal file
View File

@ -0,0 +1,74 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"lib": [
"es2017",
"dom"
], /* Specify library files to be included in the compilation. */
"allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "dist", /* Redirect output structure to the directory. */
"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}