This commit is contained in:
Tommy Parnell
2018-12-26 20:39:29 -05:00
commit e71c076567
15 changed files with 6478 additions and 0 deletions

3
.babelrc.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: [["@babel/env", { targets: { node: "6" } }]]
};

2
.gitignore vendored Normal file
View File

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

22
README.md Normal file
View File

@@ -0,0 +1,22 @@
[npm] card for Tommy Parnell
# Usage
Via npx:
```bash
npx terribledev
```
# Other
Idea and trend started by [Tierney (@bitandbang)]
To create your own, use [create-my-card].
ie: `npm init my-card`
[npm]: https://www.npmjs.com/
[tierney (@bitandbang)]: https://www.npmjs.com/package/bitandbang
[create-my-card]: https://www.npmjs.com/package/create-my-card

9
bin/index.js Normal file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env node
const verMajor = parseInt(process.versions.node.split(".")[0], 10);
if (verMajor <= 6) {
require("../dist/node6-card");
} else {
require("../dist/card");
}

34
index.html Normal file
View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<title>Tommy Parnell (@terribledev) npm card</title>
<style>
.card {
border-radius: 15px;
border: 2px solid #73ad21;
padding: 5px;
margin: 25px;
background: black;
padding-left: 25px;
padding-right: 25px;
width: fit-content;
background-image: url("http://cdn.backgroundhost.com/backgrounds/subtlepatterns/burried.png");
}
</style>
</head>
<body>
<div class="card"><pre>
<span style="color:#AAA"> <span style="color:#AAA">Tommy Parnell<span style="color:#AAA"><span style="color:#0A0"> / <span style="color:#AAA"><span style="color:#0AA">terribledev<span style="color:#AAA"><span style="color:#FFF"></span></span></span></span></span></span></span></span>
<span style="color:#AAA"><b><span style="color:#55F">Work<span style="color:#AAA">: <span style="color:#FFF"><span style="color:#AAA">Sr. Software Engineer<span style="color:#FFF"></span></span></span></span></span></b></span>
<span style="color:#AAA"><b>Twitter: </b><span style="color:#FFF"><a href="https://twitter.com/terribledev"><span style="color:#AAA">https://twitter.com/<span style="color:#0AA">terribledev<span style="color:#AAA"><span style="color:#FFF"></a></span></span></span></span></span></span>
<span style="color:#AAA"><b>npm: </b><span style="color:#FFF"><a href="https://www.npmjs.com/~terribledev"><span style="color:#AAA">https://www.npmjs.com/<span style="color:#A00">~terribledev<span style="color:#AAA"><span style="color:#FFF"></a></span></span></span></span></span></span>
<span style="color:#AAA"><b>GitHub: </b><span style="color:#FFF"><a href="https://github.com/terribledev"><span style="color:#AAA">https://github.com/<span style="color:#0A0">terribledev<span style="color:#AAA"><span style="color:#FFF"></a></span></span></span></span></span></span>
<span style="color:#AAA"><b>LinkedIn: </b><span style="color:#FFF"><a href="https://www.linkedin.com/in/tommy-parnell-63a72224"><span style="color:#AAA">https://www.linkedin.com/in/<span style="color:#55F">tommy-parnell-63a72224<span style="color:#AAA"><span style="color:#FFF"></a></span></span></span></span></span></span>
<span style="color:#AAA"><b>Web: </b><span style="color:#FFF"><a href="https://blog.terribledev.io"><span style="color:#AAA"><span style="color:#0AA">https://blog.terribledev.io<span style="color:#AAA"><span style="color:#FFF"></a></span></span></span></span></span></span>
<span style="color:#AAA"><b>Card: </b><span style="color:#FFF"><span style="color:#AAA"><span style="color:#A00">npx<span style="color:#AAA"> terribledev<span style="color:#FFF"></span></span></span></span></span></span>
</pre></div>
</body>
</html>

5996
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

96
package.json Normal file
View File

@@ -0,0 +1,96 @@
{
"name": "terribledev",
"version": "0.0.1",
"description": "Personal npm card for Tommy Parnell (@terribledev)",
"main": "index.html",
"repository": {
"type": "git",
"url": "https://github.com/terribledev/terribledev.git"
},
"scripts": {
"prepare": "node src/htmlify",
"prepublishOnly": "webpack"
},
"bin": {
"terribledev": "bin/index.js"
},
"files": [
"bin",
"dist",
"index.html"
],
"keywords": [
"card",
"npm",
"npm card",
"npx",
"npx card",
"business card"
],
"author": "Tommy Parnell",
"license": "ISC",
"dependencies": {},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.2.3",
"ansi-to-html": "^0.6.9",
"babel-loader": "^8.0.4",
"boxen": "^2.1.0",
"chalk": "^2.4.1",
"lodash.get": "^4.4.2",
"webpack": "^4.28.1",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-cli": "^3.1.2"
},
"myCard": {
"info": {
"name": "Tommy Parnell",
"handle": "terribledev",
"twitter": "terribledev",
"npm": "terribledev",
"github": "terribledev",
"linkedin": "tommy-parnell-63a72224",
"web": "https://blog.terribledev.io",
"work": "Sr. Software Engineer"
},
"data": [
" <white>{{name}}</><green> / </><cyan>{{handle}}</>",
"",
{
"label": "<blue>Work</>",
"text": "{{work}}"
},
"",
{
"label": "Twitter",
"text": "https://twitter.com/<cyan>{{twitter}}</>",
"when": "{{twitter}}"
},
{
"label": "npm",
"text": "https://www.npmjs.com/<red>~{{npm}}</>",
"when": "{{npm}}"
},
{
"label": "GitHub",
"text": "https://github.com/<green>{{github}}</>",
"when": "{{github}}"
},
{
"label": "LinkedIn",
"text": "https://www.linkedin.com/in/<blue>{{linkedin}}</>",
"when": "{{linkedin}}"
},
{
"label": "Web",
"text": "<cyan>{{web}}</>",
"when": "{{web}}"
},
"",
{
"label": "Card",
"text": "<red>npx</> {{_packageName}}"
}
]
}
}

22
src/card.html Normal file
View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ cardTitle }} npm card</title>
<style>
.card {
border-radius: 15px;
border: 2px solid #73ad21;
padding: 5px;
margin: 25px;
background: black;
padding-left: 25px;
padding-right: 25px;
width: fit-content;
background-image: url("http://cdn.backgroundhost.com/backgrounds/subtlepatterns/burried.png");
}
</style>
</head>
<body>
<div class="card">{{ card }}</div>
</body>
</html>

13
src/card.js Normal file
View File

@@ -0,0 +1,13 @@
"use strict";
/*
* Note that it's important that sources are all under a single level of directory
* like src and webpack bundle output is dist. That way, all the relative
* require paths such as `../` continue to work as is.
*/
const xrequire = eval(`require`);
const makeCard = require("./make-card");
const myPkg = xrequire("../package.json");
console.log(makeCard(myPkg).boxenText);

28
src/color-marks.js Normal file
View File

@@ -0,0 +1,28 @@
"use strict";
const get = require("lodash.get");
const chalk = require("chalk");
//
// convert color markers in a string to terminal color codes with chalk
// color marker format is "<red>red text</red><blue.bold>blue bold text</blue.bold>"
// the end marker can simply be "</>" also
// the marker is converted to chalk methods directly, for example:
// - chalk.red is called for "<red>"
// - chalk.blue.bold is called for "<blue.bold>"
//
function format(s) {
return s.replace(/<([a-z.]+)>([^<]+)($|<\/[^>]*>)/g, (a, b, c) => {
return get(chalk, b)(c);
});
}
// remove the color marker like <red>text</> from strings
function remove(s) {
return s.replace(/<[^>]*>/g, "").trim();
}
module.exports = {
format,
remove
};

56
src/htmlify.js Normal file
View File

@@ -0,0 +1,56 @@
"use strict";
/*
* Note that it's important that sources are all under a single level of directory
* like src and webpack bundle output is dist. That way, all the relative
* require paths such as `../` continue to work as is.
*/
process.env.FORCE_COLOR = 1;
const Path = require("path");
const xrequire = eval(`require`);
const makeCard = require("./make-card");
const AnsiToHtml = require("ansi-to-html");
const myPkg = xrequire("../package.json");
const Fs = require("fs");
const colorMarks = require("./color-marks");
const get = require("lodash.get");
function makeHtmlCard(pkg) {
const myCard = pkg.myCard;
const info = Object.assign({ _packageName: pkg.name }, myCard.info);
// replace {{token}} in string with info[token]
const processString = str => str.replace(/{{([^}]+)}}/g, (a, b) => get(info, b, ""));
pkg.myCard.data = pkg.myCard.data.map(l => {
if (typeof l !== "string") {
if (l.hasOwnProperty("link")) {
l._link = processString(l.link);
} else {
const link = processString(colorMarks.remove(l.text));
if (link.indexOf("http") >= 0) {
l._link = link;
}
}
}
return l;
});
const card = makeCard(pkg);
const ansi = new AnsiToHtml();
const html = card.cardLines.map(l => ansi.toHtml(l)).join("\n");
const template = Fs.readFileSync(Path.join(__dirname, "card.html")).toString();
Fs.writeFileSync(
"index.html",
template.replace("{{ cardTitle }}", `${info.name} (@${info.handle})`).replace(
"{{ card }}",
`<pre>
${html}
</pre>`
)
);
}
makeHtmlCard(myPkg);

102
src/make-card.js Normal file
View File

@@ -0,0 +1,102 @@
"use strict";
/*
* Note that it's important that sources are all under a single level of directory
* like src and webpack bundle output is dist. That way, all the relative
* require paths such as `../` continue to work as is.
*/
const boxen = require("boxen");
const chalk = require("chalk");
const get = require("lodash.get");
const cardStyle = require("./style.js");
const colorMarks = require("./color-marks");
module.exports = makeCard;
function makeCard(pkg) {
// get myCard info from package
const myCard = pkg.myCard;
const info = Object.assign({ _packageName: pkg.name }, myCard.info);
const data = myCard.data;
// replace {{token}} in string with info[token]
const processString = str => str.replace(/{{([^}]+)}}/g, (a, b) => get(info, b, ""));
// find the longest label string and its corresponding URL
// for later padding of spaces to do alignment
const maxLens = data.reduce(
(a, x) => {
// if line is a literal string or has no label, skip
if (typeof x === "string" || !x.hasOwnProperty("label")) return a;
a.label = Math.max(a.label, colorMarks.remove(x.label).length);
a.text = Math.max(a.text, colorMarks.remove(x.text).length);
return a;
},
{ label: 0, text: 0 }
);
const defaultStyle = Object.assign({ label: x => x, text: x => x }, cardStyle._default);
const cardLines = data.reduce((a, x) => {
let line;
// line has when field and it's empty, so skip it
if (x.when && processString(x.when).trim() === "") {
return a;
}
// line has only text and no label, so take it as literal string
if (!x.hasOwnProperty("label") && x.hasOwnProperty("text")) {
x = x.text || "";
}
if (typeof x === "string") {
// process a string literal line directly
line = defaultStyle.text(colorMarks.format(processString(x)));
} else {
// replace any info token in label and text
const xLabel = processString(x.label);
const xText = processString(x.text);
// get label literal without any color markers
const label = colorMarks.remove(xLabel);
// get style for the label
const style = Object.assign(
{},
defaultStyle,
cardStyle[label] || cardStyle[label.toLowerCase()]
);
// add leading spaces for alignment
const pad = x.hasOwnProperty("pad")
? x.pad
: new Array(maxLens.label - label.length + 1).join(" ");
line =
pad +
style.label(colorMarks.format(xLabel)) +
style.text(colorMarks.format(xText), x._link);
}
a.push(line);
return a;
}, []);
// join all the text lines into a single string with newline
const cardText = cardLines.join("\n");
// get options for boxen
const boxenStyle = cardStyle._boxen || {
padding: 1,
margin: 1,
borderColor: "green",
borderStyle: "round"
};
const boxenText = boxen(cardText, boxenStyle);
return {
cardLines,
cardText,
boxenText
};
}

30
src/style.js Normal file
View File

@@ -0,0 +1,30 @@
"use strict";
const chalk = require("chalk");
const linkify = (text, link) => {
return link ? `<a href="${link}">${text}</a>` : text;
};
module.exports = {
// style override for Work label
work: {
text: x => chalk.white(x)
},
// style override for Card label
card: {
text: x => chalk.white(x)
},
// any label without a style defined will use this
_default: {
label: x => (x && chalk.white.bold(x + ": ")) || " ",
text: (x, link) => linkify(chalk.white(x), link)
},
// options for boxen
_boxen: {
padding: 1,
margin: 1,
borderColor: "green",
borderStyle: "round"
}
};

14
stubs/term-size.js Normal file
View File

@@ -0,0 +1,14 @@
"use strict";
const xrequire = eval(`require`);
try {
module.exports = xrequire("term-size");
} catch {
module.exports = function() {
return {
rows: 24,
columns: 80
};
};
}

51
webpack.config.js Normal file
View File

@@ -0,0 +1,51 @@
"use strict";
const Path = require("path");
const webpack = require("webpack");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const base = {
mode: process.env.ANALYZE_BUNDLE ? "development" : "production",
//devtool: "source-map",
entry: {
"card.js": Path.resolve("src/card.js")
},
plugins: [
process.env.ANALYZE_BUNDLE && new BundleAnalyzerPlugin()
].filter(x => x),
resolve: {
symlinks: false, // don't resolve symlinks to their real path
alias: {
"term-size": Path.resolve("stubs/term-size.js")
}
},
output: {
filename: `[name]`,
path: Path.resolve("dist"),
libraryTarget: "commonjs2"
},
target: "node",
node: {
__filename: false,
__dirname: false
}
};
const node6 = Object.assign({}, base, {
module: {
rules: [
{
test: /\.js$/,
exclude: x => x.indexOf("node_modules") > 0,
use: "babel-loader"
}
]
},
output: {
filename: `node6-[name]`,
path: Path.resolve("dist"),
libraryTarget: "commonjs2"
}
});
module.exports = [base, node6];