ts-add-js-extension
Version:
Add .js extension to each relative ESM import and export statement in JavaScript file
253 lines (252 loc) • 7.71 kB
JavaScript
import fs from "fs";
import path from "path";
import pkg from "./package.js";
import { guard } from "./type.js";
const commandKeyWords = {
help: {
isMandatory: false,
keyword: "help",
},
version: {
isMandatory: false,
keyword: "version",
},
dir: {
isMandatory: true,
keyword: "dir",
},
include: {
isMandatory: false,
keyword: "include",
},
showChanges: {
type: "deprecated",
isMandatory: false,
keyword: "showchanges",
reason: "The function showchanges is deprecated in favor of `showprogress`",
},
assignment: {
assign: "=",
key: "--",
},
};
class TokenParser {
token;
constructor(token) {
this.token = token;
}
parseVersion = () => {
const { keyword } = commandKeyWords.version;
if (this.token.key !== keyword) {
return {
exists: false,
};
}
return {
type: keyword,
exists: true,
value: pkg.version,
};
};
parseHelp = () => {
const { keyword } = commandKeyWords.help;
if (this.token.key !== commandKeyWords.help.keyword) {
return {
exists: false,
};
}
return {
type: keyword,
exists: true,
value: fs.readFileSync("public/help.md", { encoding: "utf-8" }),
};
};
parseDir = () => {
const { keyword } = commandKeyWords.dir;
if (this.token.key !== commandKeyWords.dir.keyword) {
return {
exists: false,
};
}
return {
type: keyword,
exists: true,
value: guard({
value: this.token.value.split(" ").at(0),
error: new Error("There must be at least one element in values for dir"),
}),
};
};
parseInclude = () => {
const { keyword } = commandKeyWords.include;
if (this.token.key !== commandKeyWords.include.keyword) {
return {
exists: false,
};
}
return {
type: keyword,
exists: true,
value: this.token.value.split(" "),
};
};
parseShowChanges = () => {
const { keyword } = commandKeyWords.showChanges;
const { key, value } = this.token;
if (key !== commandKeyWords.showChanges.keyword) {
return {
exists: false,
};
}
if (value === "true" || value === "false") {
return {
type: keyword,
exists: true,
value: JSON.parse(value),
};
}
throw new Error(`${key}=${value} is invalid, it can only receive boolean value`);
};
processNonRecognisableToken = () => {
return {
type: "invalid",
reason: `${this.token.key}=${this.token.value} token cannot be recognized`,
token: this.token,
};
};
}
class ParseArgs {
tokens;
constructor(args) {
this.tokens = this.tokenize(args);
}
static create = (arg) => {
const tokens = arg.split(commandKeyWords.assignment.key);
const result = ParseArgs.checkPackageName(tokens.at(0));
if (result.isInvalid) {
throw result.error;
}
if (tokens.includes("add")) {
console.log("The \"add\" in the command can be removed, as it is only used for backward compatibility");
}
return new this(tokens
.map((token) => {
return token === "add" ? "" : token;
})
.slice(1));
};
static checkPackageName = (name) => {
const packageName = guard({
value: name,
error: new Error("The pkg name is undefined"),
});
return packageName.includes(pkg.name)
? {
isInvalid: false,
}
: {
isInvalid: true,
error: new Error(`The pkg name "${packageName}" passed is invalid`),
};
};
tokenize = (args) => {
const { assign } = commandKeyWords.assignment;
return args
.flatMap((arg) => {
if (arg.includes(assign)) {
return [arg];
}
const [nullableKey, ...value] = arg.split(" ");
const key = guard({
value: nullableKey,
error: new Error("Key cannot be undefined after being split"),
});
return [`${key}${assign}${value.join(" ")}`];
})
.map((args) => {
const [key, value] = args.split(assign);
return {
key: guard({
value: key,
error: new Error("Key cannot be undefined after being flat mapped"),
}),
value: guard({
value,
error: new Error("Value cannot be undefined after being flat mapped"),
}).trim(),
};
});
};
asVersion = () => {
return this.tokens.reduce((result, token) => {
if (result.exists) {
return result;
}
return new TokenParser(token).parseVersion();
}, {
exists: false,
});
};
asHelp = () => {
if (!this.tokens.length) {
return {
type: "help",
exists: true,
value: fs.readFileSync(path.join("public", "help.md"), {
encoding: "utf-8",
}),
};
}
return this.tokens.reduce((result, token) => {
if (result.exists) {
return result;
}
return new TokenParser(token).parseHelp();
}, { exists: false });
};
asOperation = () => {
const processedToken = this.tokens.map((token) => {
const parser = new TokenParser(token);
const dir = parser.parseDir();
if (dir.exists) {
return dir;
}
const include = parser.parseInclude();
if (include.exists) {
return include;
}
const showChanges = parser.parseShowChanges();
if (showChanges.exists) {
return showChanges;
}
return parser.processNonRecognisableToken();
});
processedToken
.flatMap((node) => {
return node.type !== "invalid" ? [] : [node];
})
.forEach((node) => {
console.log(`The "${JSON.stringify(node.token, undefined, 4)}" in the command is invalid as ${node.reason}. So please remove it`);
});
const nodes = processedToken.flatMap((node) => {
return node.type === "invalid" ? [] : [node];
});
return {
dir: guard({
value: nodes.find((node) => {
return node.type === "dir";
})?.value,
error: new Error("dir is a mandatory field, it should be present to know which dir it should operate on"),
}),
// optional
include: nodes.find((node) => {
return node.type === "include";
})?.value,
showChanges: nodes.find((node) => {
return node.type === "showchanges";
})?.value,
};
};
}
export default ParseArgs;
//# sourceMappingURL=cli-command-parser.js.map