Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
joeldenning committed Oct 24, 2019
1 parent 992f4a9 commit 205c6b8
Show file tree
Hide file tree
Showing 9 changed files with 4,045 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,5 @@ typings/

# next.js build output
.next

.DS_Store
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# narn

Never have to switch between npm and yarn commands ever again
20 changes: 20 additions & 0 deletions bin/narn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env node
const { spawn } = require("child_process");
const { detectYarn, getYarnArgs, getNpmArgs } = require("../lib/narn-lib.js");

async function runPackageManager() {
const isYarn = await detectYarn();
const narnArgs = process.argv.slice(2);

const command = isYarn ? "yarn" : "npm";
const commandArgs = isYarn ? getYarnArgs(narnArgs) : getNpmArgs(narnArgs);

console.info(`${command} ${commandArgs.join(" ")}`);

spawn(command, commandArgs, { stdio: "inherit" });
}

runPackageManager().catch(err => {
console.error(err);
process.exit(1);
});
52 changes: 52 additions & 0 deletions lib/narn-lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const fs = require("fs");
const path = require("path");
const minimist = require("minimist");

exports.detectYarn = function detectYarn() {
return new Promise((resolve, reject) => {
fs.access(
path.resolve(process.cwd(), "package-lock.json"),
fs.constants.F_OK,
noPackageLock => {
resolve(Boolean(noPackageLock));
}
);
});
};

exports.getYarnArgs = narnArgs => narnArgs;

exports.getNpmArgs = narnArgs => {
const yarnArgs = minimist(narnArgs);
const yarnCommands = yarnArgs._;
const yarnTarget = yarnCommands.length > 0 ? yarnCommands[0] : "install";
const yarnSubCommands = yarnCommands.slice(1);
let npmTarget;
let npmArgs;

switch (yarnTarget) {
case "install":
npmTarget = "install";
npmArgs = [];
break;
case "add":
npmTarget = "install";
const packages = yarnSubCommands.map(packageToAdd =>
packageToAdd.lastIndexOf("@") > 0
? packageToAdd
: `${packageToAdd}@latest`
);
npmArgs = ["--save", ...packages];
break;
case "remove":
npmTarget = "uninstall";
npmArgs = yarnSubCommands;
break;
default:
npmTarget = "run";
npmArgs = narnArgs;
break;
}

return [npmTarget, ...npmArgs];
};
31 changes: 31 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "narn",
"version": "1.0.0",
"main": "lib/narn-lib.js",
"bin": {
"narn": "bin/narn.js"
},
"repository": "[email protected]:joeldenning/narn.git",
"author": "Joel Denning <[email protected]>",
"homepage": "https://github.com/joeldenning/narn",
"license": "MIT",
"scripts": {
"test": "jest --env=node",
"prettier": "prettier 'bin/**/*' --write"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged"
}
},
"devDependencies": {
"@types/jest": "^24.0.19",
"husky": "^3.0.9",
"jest": "^24.9.0",
"jest-cli": "^24.9.0",
"minimist": "^1.2.0",
"prettier": "^1.18.2",
"pretty-quick": "^2.0.0"
},
"dependencies": {}
}
40 changes: 40 additions & 0 deletions test/add.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const { getNpmArgs } = require("../lib/narn-lib");

describe("narn add", () => {
it("forces packages to be saved", () => {
expect(getNpmArgs(["add", "lodash"]).slice(0, 2)).toEqual([
"install",
"--save"
]);
});

it("can install multiple packages with their semantic version specified", () => {
expect(getNpmArgs(["add", "[email protected]", "react-dom@^16.10.0"])).toEqual([
"install",
"--save",
"[email protected]",
"react-dom@^16.10.0"
]);
});

it("forces latest version of package when semantic version is omitted, same as yarn add", () => {
expect(getNpmArgs(["add", "lodash"])).toEqual([
"install",
"--save",
"lodash@latest"
]);
});

it("works with scoped packages", () => {
expect(getNpmArgs(["add", "@openmrs/esm-api"])).toEqual([
"install",
"--save",
"@openmrs/esm-api@latest"
]);
expect(getNpmArgs(["add", "@openmrs/esm-api@~1.0.0"])).toEqual([
"install",
"--save",
"@openmrs/esm-api@~1.0.0"
]);
});
});
11 changes: 11 additions & 0 deletions test/install.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { getNpmArgs } = require("../lib/narn-lib");

describe("narn install", () => {
it("defaults to npm install if no args are provided", () => {
expect(getNpmArgs([])).toEqual(["install"]);
});

it("works when install is specified", () => {
expect(getNpmArgs(["install"])).toEqual(["install"]);
});
});
11 changes: 11 additions & 0 deletions test/remove.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { getNpmArgs } = require("../lib/narn-lib");

describe("narn remove", () => {
it("removes packages", () => {
expect(getNpmArgs(["remove", "@angular/cli", "@angular/core"])).toEqual([
"uninstall",
"@angular/cli",
"@angular/core"
]);
});
});
Loading

0 comments on commit 205c6b8

Please sign in to comment.