Socket
Socket
Sign inDemoInstall

watskeburt

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

watskeburt - npm Package Compare versions

Comparing version 4.0.1 to 4.0.2

102

dist/cli.js

@@ -17,58 +17,58 @@ import { EOL } from "node:os";

export async function cli(
pArguments = process.argv.slice(2),
pOutStream = process.stdout,
pErrorStream = process.stderr,
pErrorExitCode = 1,
pArguments = process.argv.slice(2),
pOutStream = process.stdout,
pErrorStream = process.stderr,
pErrorExitCode = 1,
) {
try {
const lArguments = getArguments(pArguments);
if (lArguments.values.help) {
pOutStream.write(HELP_MESSAGE);
return;
}
if (lArguments.values.version) {
pOutStream.write(`${VERSION}${EOL}`);
return;
}
if (!outputTypeIsValid(lArguments.values.outputType)) {
pErrorStream.write(
`error: option '-T, --outputType <type>' argument '${lArguments.values.outputType}' is invalid. Allowed choices are json, regex.${EOL}`,
);
process.exitCode = pErrorExitCode;
return;
}
const lResult = await list({
...lArguments.values,
oldRevision: lArguments.positionals[0],
newRevision: lArguments.positionals[1],
});
pOutStream.write(`${lResult}${EOL}`);
} catch (pError) {
pErrorStream.write(`${EOL}ERROR: ${pError.message}${EOL}${EOL}`);
process.exitCode = pErrorExitCode;
}
try {
const lArguments = getArguments(pArguments);
if (lArguments.values.help) {
pOutStream.write(HELP_MESSAGE);
return;
}
if (lArguments.values.version) {
pOutStream.write(`${VERSION}${EOL}`);
return;
}
if (!outputTypeIsValid(lArguments.values.outputType)) {
pErrorStream.write(
`error: option '-T, --outputType <type>' argument '${lArguments.values.outputType}' is invalid. Allowed choices are json, regex.${EOL}`,
);
process.exitCode = pErrorExitCode;
return;
}
const lResult = await list({
...lArguments.values,
oldRevision: lArguments.positionals[0],
newRevision: lArguments.positionals[1],
});
pOutStream.write(`${lResult}${EOL}`);
} catch (pError) {
pErrorStream.write(`${EOL}ERROR: ${pError.message}${EOL}${EOL}`);
process.exitCode = pErrorExitCode;
}
}
function getArguments(pArguments) {
return parseArgs({
args: pArguments,
options: {
outputType: {
type: "string",
short: "T",
default: "regex",
},
trackedOnly: {
type: "boolean",
default: false,
},
help: { type: "boolean", short: "h", default: false },
version: { type: "boolean", short: "V", default: false },
},
strict: true,
allowPositionals: true,
tokens: false,
});
return parseArgs({
args: pArguments,
options: {
outputType: {
type: "string",
short: "T",
default: "regex",
},
trackedOnly: {
type: "boolean",
default: false,
},
help: { type: "boolean", short: "h", default: false },
version: { type: "boolean", short: "V", default: false },
},
strict: true,
allowPositionals: true,
tokens: false,
});
}
function outputTypeIsValid(pOutputType) {
return ["json", "regex"].includes(pOutputType);
return ["json", "regex"].includes(pOutputType);
}
import formatAsRegex from "./regex.js";
import formatAsJSON from "./json.js";
const OUTPUT_TYPE_TO_FUNCTION = new Map([
["regex", formatAsRegex],
["json", formatAsJSON],
["regex", formatAsRegex],
["json", formatAsJSON],
]);
export function format(pChanges, pOutputType) {
return OUTPUT_TYPE_TO_FUNCTION.get(pOutputType)(pChanges);
return OUTPUT_TYPE_TO_FUNCTION.get(pOutputType)(pChanges);
}
const INDENT = 2;
export default function formatAsJSON(pChanges) {
return JSON.stringify(pChanges, null, INDENT);
return JSON.stringify(pChanges, null, INDENT);
}
import { extname } from "node:path";
const DEFAULT_EXTENSIONS = new Set([
".cjs",
".cjsx",
".coffee",
".csx",
".cts",
".js",
".json",
".jsx",
".litcoffee",
".ls",
".mjs",
".mts",
".svelte",
".ts",
".tsx",
".vue",
".vuex",
".cjs",
".cjsx",
".coffee",
".csx",
".cts",
".js",
".json",
".jsx",
".litcoffee",
".ls",
".mjs",
".mts",
".svelte",
".ts",
".tsx",
".vue",
".vuex",
]);
const DEFAULT_CHANGE_TYPES = new Set([
"modified",
"added",
"renamed",
"copied",
"untracked",
"modified",
"added",
"renamed",
"copied",
"untracked",
]);
export default function formatAsRegex(
pChanges,
pExtensions = DEFAULT_EXTENSIONS,
pChangeTypes = DEFAULT_CHANGE_TYPES,
pChanges,
pExtensions = DEFAULT_EXTENSIONS,
pChangeTypes = DEFAULT_CHANGE_TYPES,
) {
const lChanges = pChanges
.filter(
(pChange) =>
pChangeTypes.has(pChange.type) &&
pExtensions.has(extname(pChange.name)),
)
.map(({ name }) => name.replace(/\\/g, "\\\\").replace(/\./g, "[.]"))
.join("|");
return `^(${lChanges})$`;
const lChanges = pChanges
.filter(
(pChange) =>
pChangeTypes.has(pChange.type) &&
pExtensions.has(extname(pChange.name)),
)
.map(({ name }) => name.replace(/\\/g, "\\\\").replace(/\./g, "[.]"))
.join("|");
return `^(${lChanges})$`;
}
import { spawn } from "node:child_process";
export async function getStatusShort(pSpawnFunction = spawn) {
const lErrorMap = new Map([
[129, `'${process.cwd()}' does not seem to be a git repository`],
]);
const lResult = await getGitResult(
["status", "--porcelain"],
lErrorMap,
pSpawnFunction,
);
return lResult;
const lErrorMap = new Map([
[129, `'${process.cwd()}' does not seem to be a git repository`],
]);
const lResult = await getGitResult(
["status", "--porcelain"],
lErrorMap,
pSpawnFunction,
);
return lResult;
}
export async function getDiffLines(
pOldRevision,
pNewRevision,
pSpawnFunction = spawn,
pOldRevision,
pNewRevision,
pSpawnFunction = spawn,
) {
const lErrorMap = new Map([
[
128,
`revision '${pOldRevision}' ${pNewRevision ? `(or '${pNewRevision}') ` : ""}unknown`,
],
[129, `'${process.cwd()}' does not seem to be a git repository`],
]);
const lResult = await getGitResult(
pNewRevision
? ["diff", pOldRevision, pNewRevision, "--name-status"]
: ["diff", pOldRevision, "--name-status"],
lErrorMap,
pSpawnFunction,
);
return lResult;
const lErrorMap = new Map([
[
128,
`revision '${pOldRevision}' ${pNewRevision ? `(or '${pNewRevision}') ` : ""}unknown`,
],
[129, `'${process.cwd()}' does not seem to be a git repository`],
]);
const lResult = await getGitResult(
pNewRevision
? ["diff", pOldRevision, pNewRevision, "--name-status"]
: ["diff", pOldRevision, "--name-status"],
lErrorMap,
pSpawnFunction,
);
return lResult;
}
export async function getSHA(pSpawnFunction = spawn) {
const lSha1Length = 40;
const lResult = await getGitResult(
["rev-parse", "HEAD"],
new Map(),
pSpawnFunction,
);
return lResult.slice(0, lSha1Length);
const lSha1Length = 40;
const lResult = await getGitResult(
["rev-parse", "HEAD"],
new Map(),
pSpawnFunction,
);
return lResult.slice(0, lSha1Length);
}
function getGitResult(pArguments, pErrorMap, pSpawnFunction) {
const lGit = pSpawnFunction("git", pArguments, {
cwd: process.cwd(),
env: process.env,
});
let lStdOutData = "";
let lStdErrorData = "";
return new Promise((pResolve, pReject) => {
lGit.stdout?.on("data", (pData) => {
lStdOutData = lStdOutData.concat(pData);
});
lGit.stderr?.on("data", (pData) => {
lStdErrorData = lStdErrorData.concat(pData);
});
lGit.on("close", (pCode) => {
if (pCode === 0) {
pResolve(stringifyOutStream(lStdOutData));
} else {
pReject(
new Error(
pErrorMap.get(pCode ?? 0) ||
`internal git error: ${pCode} (${stringifyOutStream(lStdErrorData)})`,
),
);
}
});
lGit.on("error", (pError) => {
if (pError?.code === "ENOENT") {
pReject(new Error("git executable not found"));
} else {
pReject(new Error(`internal spawn error: ${pError}`));
}
});
});
const lGit = pSpawnFunction("git", pArguments, {
cwd: process.cwd(),
env: process.env,
});
let lStdOutData = "";
let lStdErrorData = "";
return new Promise((pResolve, pReject) => {
lGit.stdout?.on("data", (pData) => {
lStdOutData = lStdOutData.concat(pData);
});
lGit.stderr?.on("data", (pData) => {
lStdErrorData = lStdErrorData.concat(pData);
});
lGit.on("close", (pCode) => {
if (pCode === 0) {
pResolve(stringifyOutStream(lStdOutData));
} else {
pReject(
new Error(
pErrorMap.get(pCode ?? 0) ||
`internal git error: ${pCode} (${stringifyOutStream(lStdErrorData)})`,
),
);
}
});
lGit.on("error", (pError) => {
if (pError?.code === "ENOENT") {
pReject(new Error("git executable not found"));
} else {
pReject(new Error(`internal spawn error: ${pError}`));
}
});
});
}
function stringifyOutStream(pBufferOrString) {
if (pBufferOrString instanceof Buffer) {
return pBufferOrString.toString("utf8");
} else {
return pBufferOrString;
}
if (pBufferOrString instanceof Buffer) {
return pBufferOrString.toString("utf8");
} else {
return pBufferOrString;
}
}

@@ -5,24 +5,24 @@ import { parseDiffLines } from "./parse-diff-lines.js";

export async function list(pOptions) {
const lOldRevision = pOptions?.oldRevision || (await primitives.getSHA());
const lOptions = pOptions || {};
const [lDiffLines, lStatusLines] = await Promise.all([
primitives.getDiffLines(lOldRevision, pOptions?.newRevision),
!lOptions.trackedOnly ? primitives.getStatusShort() : "",
]);
let lChanges = parseDiffLines(lDiffLines);
if (!lOptions.trackedOnly) {
lChanges = lChanges.concat(
parseStatusLines(lStatusLines).filter(
({ type: changeType }) => changeType === "untracked",
),
);
}
if (!lOptions.outputType) {
return lChanges;
}
const { format } = await import("./format/format.js");
return format(lChanges, lOptions.outputType);
const lOldRevision = pOptions?.oldRevision || (await primitives.getSHA());
const lOptions = pOptions || {};
const [lDiffLines, lStatusLines] = await Promise.all([
primitives.getDiffLines(lOldRevision, pOptions?.newRevision),
!lOptions.trackedOnly ? primitives.getStatusShort() : "",
]);
let lChanges = parseDiffLines(lDiffLines);
if (!lOptions.trackedOnly) {
lChanges = lChanges.concat(
parseStatusLines(lStatusLines).filter(
({ type: changeType }) => changeType === "untracked",
),
);
}
if (!lOptions.outputType) {
return lChanges;
}
const { format } = await import("./format/format.js");
return format(lChanges, lOptions.outputType);
}
export function getSHA() {
return primitives.getSHA();
return primitives.getSHA();
}
const CHANGE_CHAR_2_CHANGE_TYPE = new Map([
["A", "added"],
["C", "copied"],
["D", "deleted"],
["M", "modified"],
["R", "renamed"],
["T", "type changed"],
["U", "unmerged"],
["B", "pairing broken"],
[" ", "unmodified"],
["?", "untracked"],
["!", "ignored"],
["A", "added"],
["C", "copied"],
["D", "deleted"],
["M", "modified"],
["R", "renamed"],
["T", "type changed"],
["U", "unmerged"],
["B", "pairing broken"],
[" ", "unmodified"],
["?", "untracked"],
["!", "ignored"],
]);
export function changeChar2ChangeType(pChar) {
return CHANGE_CHAR_2_CHANGE_TYPE.get(pChar) ?? "unknown";
return CHANGE_CHAR_2_CHANGE_TYPE.get(pChar) ?? "unknown";
}
import { EOL } from "node:os";
import { changeChar2ChangeType } from "./map-change-type.js";
const DIFF_NAME_STATUS_LINE_PATTERN =
/^(?<type>[ACDMRTUXB])(?<similarity>[0-9]{3})?[ \t]+(?<name>[^ \t]+)[ \t]*(?<newName>[^ \t]+)?$/;
/^(?<type>[ACDMRTUXB])(?<similarity>[0-9]{3})?[ \t]+(?<name>[^ \t]+)[ \t]*(?<newName>[^ \t]+)?$/;
export function parseDiffLines(pString) {
return pString
.split(EOL)
.filter(Boolean)
.map(parseDiffLine)
.filter(({ name, type }) => Boolean(name) && Boolean(type));
return pString
.split(EOL)
.filter(Boolean)
.map(parseDiffLine)
.filter(({ name, type }) => Boolean(name) && Boolean(type));
}
export function parseDiffLine(pString) {
const lMatchResult = pString.match(DIFF_NAME_STATUS_LINE_PATTERN);
const lReturnValue = {};
if (lMatchResult?.groups) {
lReturnValue.type = changeChar2ChangeType(lMatchResult.groups.type);
if (lMatchResult.groups.newName) {
lReturnValue.name = lMatchResult.groups.newName;
lReturnValue.oldName = lMatchResult.groups.name;
} else {
lReturnValue.name = lMatchResult.groups.name;
}
}
return lReturnValue;
const lMatchResult = pString.match(DIFF_NAME_STATUS_LINE_PATTERN);
const lReturnValue = {};
if (lMatchResult?.groups) {
lReturnValue.type = changeChar2ChangeType(lMatchResult.groups.type);
if (lMatchResult.groups.newName) {
lReturnValue.name = lMatchResult.groups.newName;
lReturnValue.oldName = lMatchResult.groups.name;
} else {
lReturnValue.name = lMatchResult.groups.name;
}
}
return lReturnValue;
}
import { EOL } from "node:os";
import { changeChar2ChangeType } from "./map-change-type.js";
const DIFF_SHORT_STATUS_LINE_PATTERN =
/^(?<stagedType>[ ACDMRTUXB?!])(?<unStagedType>[ ACDMRTUXB?!])[ \t]+(?<name>[^ \t]+)(( -> )(?<newName>[^ \t]+))?$/;
/^(?<stagedType>[ ACDMRTUXB?!])(?<unStagedType>[ ACDMRTUXB?!])[ \t]+(?<name>[^ \t]+)(( -> )(?<newName>[^ \t]+))?$/;
export function parseStatusLines(pString) {
return pString
.split(EOL)
.filter(Boolean)
.map(parseStatusLine)
.filter(({ name, type }) => Boolean(name) && Boolean(type));
return pString
.split(EOL)
.filter(Boolean)
.map(parseStatusLine)
.filter(({ name, type }) => Boolean(name) && Boolean(type));
}
export function parseStatusLine(pString) {
const lMatchResult = pString.match(DIFF_SHORT_STATUS_LINE_PATTERN);
const lReturnValue = {};
if (lMatchResult?.groups) {
const lStagedType = changeChar2ChangeType(lMatchResult.groups.stagedType);
const lUnStagedType = changeChar2ChangeType(
lMatchResult.groups.unStagedType,
);
lReturnValue.type =
lStagedType === "unmodified" ? lUnStagedType : lStagedType;
if (lMatchResult.groups.newName) {
lReturnValue.name = lMatchResult.groups.newName;
lReturnValue.oldName = lMatchResult.groups.name;
} else {
lReturnValue.name = lMatchResult.groups.name;
}
}
return lReturnValue;
const lMatchResult = pString.match(DIFF_SHORT_STATUS_LINE_PATTERN);
const lReturnValue = {};
if (lMatchResult?.groups) {
const lStagedType = changeChar2ChangeType(lMatchResult.groups.stagedType);
const lUnStagedType = changeChar2ChangeType(
lMatchResult.groups.unStagedType,
);
lReturnValue.type =
lStagedType === "unmodified" ? lUnStagedType : lStagedType;
if (lMatchResult.groups.newName) {
lReturnValue.name = lMatchResult.groups.newName;
lReturnValue.oldName = lMatchResult.groups.name;
} else {
lReturnValue.name = lMatchResult.groups.name;
}
}
return lReturnValue;
}

@@ -1,1 +0,1 @@

export const VERSION = "4.0.1";
export const VERSION = "4.0.2";
{
"name": "watskeburt",
"version": "4.0.1",
"description": "List files changed since a git revision",
"keywords": [
"git",
"diff"
],
"homepage": "https://github.com/sverweij/watskeburt",
"repository": {
"type": "git",
"url": "git+https://github.com/sverweij/watskeburt.git"
},
"bugs": {
"url": "https://github.com/sverweij/watskeburt/issues"
},
"author": {
"name": "Sander Verweij",
"url": "https://sverweij.github.io"
},
"license": "MIT",
"bin": {
"watskeburt": "dist/run-cli.js"
},
"main": "dist/main.js",
"module": "dist/main.js",
"type": "module",
"sideEffects": false,
"exports": {
".": [
{
"types": "./types/watskeburt.d.ts",
"import": "./dist/main.js"
},
"./dist/main.js"
]
},
"types": "types/watskeburt.d.ts",
"files": [
"dist",
"!**/*.DS_Store",
"types",
"LICENSE",
"package.json",
"README.md"
],
"engines": {
"node": "^18||>=20"
},
"scripts": {
"test": "echo for test, build and static analysis scripts: see the github repository"
}
"name": "watskeburt",
"version": "4.0.2",
"description": "List files changed since a git revision",
"keywords": [
"git",
"diff"
],
"homepage": "https://github.com/sverweij/watskeburt",
"repository": {
"type": "git",
"url": "git+https://github.com/sverweij/watskeburt.git"
},
"bugs": {
"url": "https://github.com/sverweij/watskeburt/issues"
},
"author": {
"name": "Sander Verweij",
"url": "https://sverweij.github.io"
},
"license": "MIT",
"bin": {
"watskeburt": "dist/run-cli.js"
},
"main": "dist/main.js",
"module": "dist/main.js",
"type": "module",
"sideEffects": false,
"exports": {
".": [
{
"types": "./types/watskeburt.d.ts",
"import": "./dist/main.js"
},
"./dist/main.js"
]
},
"types": "types/watskeburt.d.ts",
"files": [
"dist",
"!**/*.DS_Store",
"types",
"LICENSE",
"package.json",
"README.md"
],
"engines": {
"node": "^18||>=20"
},
"scripts": {
"test": "echo for test, build and static analysis scripts: see the github repository"
}
}
export type changeType =
| "added"
| "copied"
| "deleted"
| "modified"
| "renamed"
| "type changed"
| "unmerged"
| "pairing broken"
| "unknown"
| "unmodified"
| "untracked"
| "ignored";
| "added"
| "copied"
| "deleted"
| "modified"
| "renamed"
| "type changed"
| "unmerged"
| "pairing broken"
| "unknown"
| "unmodified"
| "untracked"
| "ignored";
export interface IChange {
/**
* name of the file
*/
name: string;
/**
* how the file was changed
*/
type: changeType;
/**
* if the file was renamed: what the old file's name was
*/
oldName?: string;
/**
* name of the file
*/
name: string;
/**
* how the file was changed
*/
type: changeType;
/**
* if the file was renamed: what the old file's name was
*/
oldName?: string;
}

@@ -33,32 +33,32 @@

export interface IBaseOptions {
/**
* The revision against which to compare. When not passed defaults to the
* _current_ commit hash (if there's any)
*/
oldRevision?: string;
/**
* Newer revision against which to compare. Leave out when you want to
* compare against the working tree
*/
newRevision?: string;
/**
* When true only takes already tracked files into account.
* When false also takes untracked files into account (default)
*/
trackedOnly?: boolean;
/**
* The revision against which to compare. When not passed defaults to the
* _current_ commit hash (if there's any)
*/
oldRevision?: string;
/**
* Newer revision against which to compare. Leave out when you want to
* compare against the working tree
*/
newRevision?: string;
/**
* When true only takes already tracked files into account.
* When false also takes untracked files into account (default)
*/
trackedOnly?: boolean;
}
export interface IFormatOptions extends IBaseOptions {
/**
* The type of output to deliver.
*/
outputType: "regex" | "json";
/**
* The type of output to deliver.
*/
outputType: "regex" | "json";
}
export interface IInternalOptions extends IBaseOptions {
/**
* The type of output to deliver. undefined/ left out
* the outputType defaults to a list of `IChange`s
*/
outputType?: undefined;
/**
* The type of output to deliver. undefined/ left out
* the outputType defaults to a list of `IChange`s
*/
outputType?: undefined;
}

@@ -65,0 +65,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc