diff --git a/dist/generators.d.ts b/dist/generators.d.ts deleted file mode 100644 index 2d89c70..0000000 --- a/dist/generators.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { GeneratorOptions } from "."; -import { PackageInfo, RequiredProps } from "./utils"; -declare global { - interface String { - padEnd(maxLength: number, fillString?: string): T; - } -} -export declare type UserScriptManagerName = "tampermonkey" | "violentmonkey" | "greasemonkey"; -export declare type GrantOptions = "get" | "set" | "list" | "delete" | "unsafe" | "close" | "focus" | "change"; -declare type CommonGrants = "none"; -export declare type GreasemonkeyGrants = CommonGrants | "GM.setValue" | "GM.getValue" | "GM.listValues" | "GM.deleteValue"; -export declare type TampermonkeyGrants = CommonGrants | "GM_setValue" | "GM_getValue" | "GM_listValues" | "GM_deleteValue" | "unsafeWindow" | "window.close" | "window.focus" | "window.onurlchange"; -export declare type HeaderGenerator = (info: PackageInfo, options: RequiredProps) => string; -export declare type GeneratorMap = { - [P in UserScriptManagerName]: HeaderGenerator; -}; -export declare const generateGreasemnonkeyHeaders: HeaderGenerator; -export declare const generateTampermonkeyHeaders: HeaderGenerator; -export declare const generateViolentMonkeyHeaders: HeaderGenerator; -export {}; diff --git a/dist/generators.js b/dist/generators.js deleted file mode 100644 index c2dbdf4..0000000 --- a/dist/generators.js +++ /dev/null @@ -1,70 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generateViolentMonkeyHeaders = exports.generateTampermonkeyHeaders = exports.generateGreasemnonkeyHeaders = void 0; -const utils_1 = require("./utils"); -const makeMonkeyTags = (name = "UserScript") => [ - `// ==${name}==`, - `// ==/${name}==`, -]; -const makeMonkeyHeader = ([name, value]) => (value ? `// @${name} ${value}` : `// @${name}`); -const generateGreasemnonkeyHeaders = () => { - const [openTag, closeTag] = makeMonkeyTags(); - const headers = []; - const parsedHeaders = headers.map(makeMonkeyHeader); - return ` -${openTag} -${parsedHeaders.join("\n")} -${closeTag} -`; -}; -exports.generateGreasemnonkeyHeaders = generateGreasemnonkeyHeaders; -const LN = "\n"; -const generateTampermonkeyHeaders = ({ author, contributors = [], icon, name, description, homepage, bugs: { url: supportURL }, repository: { url: source }, version, }, { spaces, matches = [], grants = [] }) => { - const [openTag, closeTag] = makeMonkeyTags(); - const parsedAuthor = utils_1.parseAuthor(author); - const { packageName, scope } = utils_1.parseName(name); - const matchHeaders = matches.map((uri) => ["match", uri]); - const grantMap = { - set: "GM_setValue", - get: "GM_getValue", - delete: "GM_deleteValue", - list: "GM_listValues", - unsafe: "unsafeWindow", - change: "window.onurlchange", - close: "window.close", - focus: "window.focus", - }; - const grantHeaders = grants.map((grant) => ["grant", grantMap[grant]]); - if (!grantHeaders.length) - grantHeaders.push(["grant", "none"]); - const headers = [ - ["author", utils_1.formatAuthor(parsedAuthor)], - ["description", description], - ["homepage", homepage], - ...matchHeaders, - ...grantHeaders, - ["name", packageName], - ["source", source], - ["supportURL", supportURL], - ["version", version], - ]; - if (scope) - headers.push(["namespace", scope]); - if (icon) - headers.push(["icon", icon]); - if (contributors.length) { - const formatted = contributors.map((contributor) => utils_1.formatAuthor(utils_1.parseAuthor(contributor))); - headers.push(["contributors", formatted.join(", ")]); - } - const longest = utils_1.getLongest(headers.map(([key]) => key)) + spaces; - const indentedHeaders = headers.map(([key, val]) => [key.padEnd(longest), val]); - const parsedHeaders = indentedHeaders - .map(makeMonkeyHeader) - .sort(); - return [openTag, ...parsedHeaders, closeTag].join(LN); -}; -exports.generateTampermonkeyHeaders = generateTampermonkeyHeaders; -const generateViolentMonkeyHeaders = ({}) => { - return ""; -}; -exports.generateViolentMonkeyHeaders = generateViolentMonkeyHeaders; diff --git a/dist/generators/common/monkey.d.ts b/dist/generators/common/monkey.d.ts new file mode 100644 index 0000000..05c98ea --- /dev/null +++ b/dist/generators/common/monkey.d.ts @@ -0,0 +1,31 @@ +import { HeaderEntries, HeaderEntry } from ".."; +export declare type MonkeyHeader = `// @${string} ${string}` | `// @${string}`; +export declare const makeMonkeyTags: (name?: string) => readonly [openTag: string, closeTag: string]; +export declare const makeMonkeyHeader: ([name, value,]: HeaderEntry) => MonkeyHeader; +export declare const finalizeMonkeyHeaders: (headers: HeaderEntries, spaces: number) => string; diff --git a/dist/generators/common/monkey.js b/dist/generators/common/monkey.js new file mode 100644 index 0000000..5975421 --- /dev/null +++ b/dist/generators/common/monkey.js @@ -0,0 +1,24 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.finalizeMonkeyHeaders = exports.makeMonkeyHeader = exports.makeMonkeyTags = void 0; +const common_1 = require("../../utils/common"); +const makeMonkeyTags = (name = "UserScript") => [ + `// ==${name}==`, + `// ==/${name}==`, +]; +exports.makeMonkeyTags = makeMonkeyTags; +const makeMonkeyHeader = ([name, value,]) => (value ? `// @${name} ${value}` : `// @${name}`); +exports.makeMonkeyHeader = makeMonkeyHeader; +const finalizeMonkeyHeaders = (headers, spaces) => { + const [openTag, closeTag] = exports.makeMonkeyTags(); + const longest = common_1.getLongest(headers.map(([key]) => key)) + spaces; + const indentedHeaders = headers.map(([key, val]) => [ + key.padEnd(longest), + val, + ]); + const parsedHeaders = indentedHeaders + .map(exports.makeMonkeyHeader) + .sort(); + return [openTag, ...parsedHeaders, closeTag].join("\n"); +}; +exports.finalizeMonkeyHeaders = finalizeMonkeyHeaders; diff --git a/dist/generators/greasemonkey/index.d.ts b/dist/generators/greasemonkey/index.d.ts new file mode 100644 index 0000000..2f8f6ff --- /dev/null +++ b/dist/generators/greasemonkey/index.d.ts @@ -0,0 +1,3 @@ +import { HeaderGenerator } from ".."; +import { GreasemonkeyGrantOptions } from "./types"; +export declare const generateGreasemonkeyHeaders: HeaderGenerator; diff --git a/dist/generators/greasemonkey/index.js b/dist/generators/greasemonkey/index.js new file mode 100644 index 0000000..63c5aa7 --- /dev/null +++ b/dist/generators/greasemonkey/index.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateGreasemonkeyHeaders = void 0; +const __1 = require(".."); +const monkey_1 = require("../common/monkey"); +const generateGreasemonkeyHeaders = (_packageInfo, { matches = [], grants = [] }) => { + const grantMap = { + set: "GM.setValue", + get: "GM.getValue", + delete: "GM.deleteValue", + list: "GM.listValues", + notify: "GM.notification", + clip: "GM.setClipboard", + fetch: "GM.xmlHttpRequest", + unsafe: "unsafeWindow", + }; + const matchHeaders = __1.generateMatchHeaders(matches); + const grantHeaders = __1.generateGrantHeaders(grantMap, grants); + const headers = [ + ...grantHeaders, + ...matchHeaders, + ]; + return monkey_1.finalizeMonkeyHeaders(headers, 4); +}; +exports.generateGreasemonkeyHeaders = generateGreasemonkeyHeaders; diff --git a/dist/generators/greasemonkey/types.d.ts b/dist/generators/greasemonkey/types.d.ts new file mode 100644 index 0000000..132c2f8 --- /dev/null +++ b/dist/generators/greasemonkey/types.d.ts @@ -0,0 +1,7 @@ +import { CommonGrantOptions, CommonGrants, CommonHeaders, CommonRunAt, CustomHeaders } from ".."; +export declare type GreasemonkeyGrantOptions = CommonGrantOptions | "notify" | "clip" | "fetch"; +export declare type GreasemonkeyGrants = CommonGrants | "GM.setValue" | "GM.getValue" | "GM.listValues" | "GM.deleteValue" | "GM.notification" | "GM.setClipboard" | "GM.xmlHttpRequest"; +export declare type GreasemonkeyHeaders = CustomHeaders & CommonHeaders<{ + "grant": GreasemonkeyGrants; + "run-at": CommonRunAt; +}>; diff --git a/dist/generators/greasemonkey/types.js b/dist/generators/greasemonkey/types.js new file mode 100644 index 0000000..ce03781 --- /dev/null +++ b/dist/generators/greasemonkey/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/generators/index.d.ts b/dist/generators/index.d.ts new file mode 100644 index 0000000..2240cea --- /dev/null +++ b/dist/generators/index.d.ts @@ -0,0 +1,63 @@ +import { GeneratorOptions } from ".."; +import { RequiredProps } from "../utils/common"; +import { PackageInfo } from "../utils/package"; +import { GreasemonkeyGrantOptions } from "./greasemonkey/types"; +import { TampermonkeyGrantOptions } from "./tampermonkey/types"; +declare global { + interface String { + padEnd(maxLength: number, fillString?: string): T; + } +} +export declare type CommonGrantOptions = "get" | "set" | "list" | "delete" | "unsafe"; +export declare type GrantOptions = GreasemonkeyGrantOptions | TampermonkeyGrantOptions | CommonGrantOptions; +export declare type UserScriptManagerName = "tampermonkey" | "violentmonkey" | "greasemonkey"; +export declare type CommonGrants = "none" | "unsafeWindow"; +export declare type CommonRunAt = "document-start" | "document-end" | "document-idle"; +export declare type HeaderGenerator = (info: PackageInfo, options: RequiredProps, "spaces">) => string; +export declare type CommonHeaders = T & { + description: string; + exclude: string[]; + icon: string; + include: string[]; + match: string[]; + name: string; + namespace: string; + noframes: ""; + resource: string[]; + require: string[]; + version: `${number}.${number}.${number}`; + grant: string; +}; +export declare type CustomHeaders = { + contributors: string; +}; +export declare type HeaderEntry = [keyof T & string, string]; +export declare type HeaderEntries = HeaderEntry[]; +export declare const generateGrantHeaders: (grantMap: Record, grants: U[]) => HeaderEntries; +export declare const generateMatchHeaders: (matches: string[]) => HeaderEntries; diff --git a/dist/generators/index.js b/dist/generators/index.js new file mode 100644 index 0000000..d613650 --- /dev/null +++ b/dist/generators/index.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateMatchHeaders = exports.generateGrantHeaders = void 0; +const generateGrantHeaders = (grantMap, grants) => { + const grantHeaders = grants.map((grant) => [ + "grant", + grantMap[grant], + ]); + return grantHeaders.length + ? grantHeaders + : [["grant", "none"]]; +}; +exports.generateGrantHeaders = generateGrantHeaders; +const generateMatchHeaders = (matches) => { + return matches.map((uri) => ["match", uri]); +}; +exports.generateMatchHeaders = generateMatchHeaders; diff --git a/dist/generators/tampermonkey/index.d.ts b/dist/generators/tampermonkey/index.d.ts new file mode 100644 index 0000000..3f2811b --- /dev/null +++ b/dist/generators/tampermonkey/index.d.ts @@ -0,0 +1,3 @@ +import { HeaderGenerator } from ".."; +import { TampermonkeyGrantOptions } from "./types"; +export declare const generateTampermonkeyHeaders: HeaderGenerator; diff --git a/dist/generators/tampermonkey/index.js b/dist/generators/tampermonkey/index.js new file mode 100644 index 0000000..98b2021 --- /dev/null +++ b/dist/generators/tampermonkey/index.js @@ -0,0 +1,44 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateTampermonkeyHeaders = void 0; +const __1 = require(".."); +const author_1 = require("../../utils/author"); +const common_1 = require("../../utils/common"); +const monkey_1 = require("../common/monkey"); +const generateTampermonkeyHeaders = ({ author, contributors = [], icon, name, description, homepage, bugs: { url: supportURL }, repository: { url: source }, version, }, { spaces, matches = [], grants = [] }) => { + const parsedAuthor = author_1.parseAuthor(author); + const { packageName, scope } = common_1.parseName(name); + const matchHeaders = __1.generateMatchHeaders(matches); + const grantMap = { + set: "GM_setValue", + get: "GM_getValue", + delete: "GM_deleteValue", + list: "GM_listValues", + unsafe: "unsafeWindow", + change: "window.onurlchange", + close: "window.close", + focus: "window.focus", + }; + const grantHeaders = __1.generateGrantHeaders(grantMap, grants); + const headers = [ + ["author", author_1.formatAuthor(parsedAuthor)], + ["description", description], + ["homepage", homepage], + ...matchHeaders, + ...grantHeaders, + ["name", packageName], + ["source", source], + ["supportURL", supportURL], + ["version", version], + ]; + if (scope) + headers.push(["namespace", scope]); + if (icon) + headers.push(["icon", icon]); + if (contributors.length) { + const formatted = contributors.map((contributor) => author_1.formatAuthor(author_1.parseAuthor(contributor))); + headers.push(["contributors", formatted.join(", ")]); + } + return monkey_1.finalizeMonkeyHeaders(headers, spaces); +}; +exports.generateTampermonkeyHeaders = generateTampermonkeyHeaders; diff --git a/dist/generators/tampermonkey/types.d.ts b/dist/generators/tampermonkey/types.d.ts new file mode 100644 index 0000000..586a00e --- /dev/null +++ b/dist/generators/tampermonkey/types.d.ts @@ -0,0 +1,23 @@ +import { CommonGrantOptions, CommonGrants, CommonHeaders, CommonRunAt, CustomHeaders } from ".."; +export declare type TampermonkeyGrantOptions = CommonGrantOptions | "close" | "focus" | "change"; +export declare type TampermonkeyGrants = CommonGrants | "GM_setValue" | "GM_getValue" | "GM_listValues" | "GM_deleteValue" | "window.close" | "window.focus" | "window.onurlchange"; +export declare type TampermonkeyHeaders = CustomHeaders & CommonHeaders<{ + "author": string; + "homepage": string; + "homepageURL": string; + "website": string; + "source": string; + "iconURL": string; + "defaulticon": string; + "icon64": string; + "icon64URL": string; + "updateURL": string; + "downloadURL": string; + "supportURL": string; + "connect": string[]; + "run-at": CommonRunAt | "context-menu" | "document-body"; + "grant": TampermonkeyGrants; + "antifeature": `${"ads" | "tracking" | "miner"} ${string}`[]; + "unwrap": ""; + "nocompat": "Chrome" | "Opera" | "FireFox"; +}>; diff --git a/dist/generators/tampermonkey/types.js b/dist/generators/tampermonkey/types.js new file mode 100644 index 0000000..ce03781 --- /dev/null +++ b/dist/generators/tampermonkey/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/generators/violentmonkey/index.d.ts b/dist/generators/violentmonkey/index.d.ts new file mode 100644 index 0000000..207b9b9 --- /dev/null +++ b/dist/generators/violentmonkey/index.d.ts @@ -0,0 +1,2 @@ +import { CommonGrantOptions, HeaderGenerator } from ".."; +export declare const generateViolentMonkeyHeaders: HeaderGenerator; diff --git a/dist/generators/violentmonkey/index.js b/dist/generators/violentmonkey/index.js new file mode 100644 index 0000000..d3268d7 --- /dev/null +++ b/dist/generators/violentmonkey/index.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateViolentMonkeyHeaders = void 0; +const monkey_1 = require("../common/monkey"); +const generateViolentMonkeyHeaders = ({}) => { + const headers = []; + return monkey_1.finalizeMonkeyHeaders(headers, 4); +}; +exports.generateViolentMonkeyHeaders = generateViolentMonkeyHeaders; diff --git a/dist/generators/violentmonkey/types.d.ts b/dist/generators/violentmonkey/types.d.ts new file mode 100644 index 0000000..0bd770d --- /dev/null +++ b/dist/generators/violentmonkey/types.d.ts @@ -0,0 +1,2 @@ +import { CommonHeaders, CustomHeaders } from ".."; +export declare type ViolentMonkeyHeaders = CustomHeaders & CommonHeaders<{}>; diff --git a/dist/generators/violentmonkey/types.js b/dist/generators/violentmonkey/types.js new file mode 100644 index 0000000..ce03781 --- /dev/null +++ b/dist/generators/violentmonkey/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/index.d.ts b/dist/index.d.ts index 4d93d74..e1f1c07 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,10 +1,10 @@ import { GrantOptions, UserScriptManagerName } from "./generators"; -export declare type GeneratorOptions = { +export declare type GeneratorOptions = { packagePath: string; output: string; spaces?: number; matches?: string[]; - grants?: GrantOptions[]; + grants?: T[]; direct?: boolean; }; -export declare const generate: (type: UserScriptManagerName, { packagePath, output, spaces, direct, ...rest }: GeneratorOptions) => Promise; +export declare const generate: (type: UserScriptManagerName, { packagePath, output, spaces, direct, matches, ...rest }: GeneratorOptions) => Promise; diff --git a/dist/index.js b/dist/index.js index 84d6709..58ed0e1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -6,27 +6,37 @@ const chalk_1 = require("chalk"); const promises_1 = require("fs/promises"); const yargs = require("yargs"); const helpers_1 = require("yargs/helpers"); -const generators_1 = require("./generators"); -const utils_1 = require("./utils"); +const greasemonkey_1 = require("./generators/greasemonkey"); +const tampermonkey_1 = require("./generators/tampermonkey"); +const violentmonkey_1 = require("./generators/violentmonkey"); +const common_1 = require("./utils/common"); +const package_1 = require("./utils/package"); +const validators_1 = require("./utils/validators"); const names = [ "greasemonkey", "tampermonkey", "violentmonkey", ]; -const generate = async (type, { packagePath, output, spaces = 4, direct = false, ...rest }) => { +const generate = async (type, { packagePath, output, spaces = 4, direct = false, matches = [], ...rest }) => { const managerTypeMap = { - greasemonkey: generators_1.generateGreasemnonkeyHeaders, - tampermonkey: generators_1.generateTampermonkeyHeaders, - violentmonkey: generators_1.generateViolentMonkeyHeaders, + greasemonkey: greasemonkey_1.generateGreasemonkeyHeaders, + tampermonkey: tampermonkey_1.generateTampermonkeyHeaders, + violentmonkey: violentmonkey_1.generateViolentMonkeyHeaders, }; try { - const parsedPackage = await utils_1.getPackage(packagePath); + const parsedPackage = await package_1.getPackage(packagePath); if (!parsedPackage) { console.log(chalk_1.bgRed `missing or corrupted package`); return ""; } - const content = managerTypeMap[type](parsedPackage, { + const { invalid, status, valid } = validators_1.validateMatchHeaders(matches); + if (!status) { + console.log(chalk_1.bgRed `Invalid @match headers:\n` + invalid.join("\n")); + } + const handler = managerTypeMap[type]; + const content = handler(parsedPackage, { ...rest, + matches: valid, spaces, packagePath, output, @@ -82,7 +92,7 @@ const sharedOpts = { type: "number", }, }; -names.forEach((name) => cli.command(name, `generates ${utils_1.scase(name)} headers`, sharedOpts, ({ d, g = [], m = [], o, p, s }) => exports.generate(name, { +names.forEach((name) => cli.command(name, `generates ${common_1.scase(name)} headers`, sharedOpts, ({ d, g = [], m = [], o, p, s }) => exports.generate(name, { direct: !!d, matches: m.map(String), grants: g, diff --git a/dist/utils.d.ts b/dist/utils.d.ts deleted file mode 100644 index e669d46..0000000 --- a/dist/utils.d.ts +++ /dev/null @@ -1,36 +0,0 @@ -export declare type RequiredProps = T & { - [P in K]-?: T[P]; -}; -declare type PackagePerson = string | { - name: string; - email?: string; - url?: string; -}; -export declare type PackageInfo = { - author: PackagePerson; - contributors?: PackagePerson[]; - icon?: string; - license: string; - homepage: string; - name: string; - version: `${number}.${number}.${number}`; - description: string; - bugs: { - url: string; - }; - repository: { - type: "git" | "https"; - url: string; - }; -}; -export declare const getPackage: (path: string) => Promise; -export declare const getLongest: (words: string[]) => number; -export declare const scase: (text: string) => string; -export declare const mdLink: (lbl: string, href: string) => string; -export declare const formatAuthor: ({ name, email, url, }: Exclude) => string; -export declare const parseAuthor: (info: PackageInfo["author"]) => Exclude; -export declare const parseName: (name: string) => { - scope: string; - packageName: string; -}; -export {}; diff --git a/dist/utils.js b/dist/utils.js deleted file mode 100644 index 717b827..0000000 --- a/dist/utils.js +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.parseName = exports.parseAuthor = exports.formatAuthor = exports.mdLink = exports.scase = exports.getLongest = exports.getPackage = void 0; -const promises_1 = require("fs/promises"); -const getPackage = async (path) => { - try { - const contents = await promises_1.readFile(path, { encoding: "utf-8" }); - return JSON.parse(contents); - } - catch (error) { - return null; - } -}; -exports.getPackage = getPackage; -const getLongest = (words) => Math.max(...words.map(({ length }) => length)); -exports.getLongest = getLongest; -const scase = (text) => `${text[0].toUpperCase()}${text.slice(1).toLowerCase()}`; -exports.scase = scase; -const mdLink = (lbl, href) => `[${lbl}](${href})`; -exports.mdLink = mdLink; -const formatAuthor = ({ name, email, url, }) => name + (email ? ` <${email}>` : "") + (url ? ` (${url})` : ""); -exports.formatAuthor = formatAuthor; -const parseAuthor = (info) => { - if (typeof info === "object") - return info; - const authorRegex = /(\w+(?:\s\w+)?)(?:\s<(.+?)>)?(?:\s\((.+?)\))?$/i; - const match = authorRegex.exec(info); - if (!match) - throw new Error(`unable to parse author field: ${info}`); - const [_full, name, email, url] = match; - return { - name, - email, - url, - }; -}; -exports.parseAuthor = parseAuthor; -const parseName = (name) => { - const [, scope, packageName] = name.match(/(?:@([\w-]+)\/)?([\w-]+)/) || []; - return { scope, packageName }; -}; -exports.parseName = parseName; diff --git a/dist/utils/author.d.ts b/dist/utils/author.d.ts new file mode 100644 index 0000000..a6a2334 --- /dev/null +++ b/dist/utils/author.d.ts @@ -0,0 +1,3 @@ +import { PackageInfo } from "./package"; +export declare const formatAuthor: ({ name, email, url, }: Exclude) => string; +export declare const parseAuthor: (info: PackageInfo["author"]) => Exclude; diff --git a/dist/utils/author.js b/dist/utils/author.js new file mode 100644 index 0000000..0f85b2d --- /dev/null +++ b/dist/utils/author.js @@ -0,0 +1,20 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseAuthor = exports.formatAuthor = void 0; +const formatAuthor = ({ name, email, url, }) => name + (email ? ` <${email}>` : "") + (url ? ` (${url})` : ""); +exports.formatAuthor = formatAuthor; +const parseAuthor = (info) => { + if (typeof info === "object") + return info; + const authorRegex = /(\w+(?:\s\w+)?)(?:\s<(.+?)>)?(?:\s\((.+?)\))?$/i; + const match = authorRegex.exec(info); + if (!match) + throw new Error(`unable to parse author field: ${info}`); + const [_full, name, email, url] = match; + return { + name, + email, + url, + }; +}; +exports.parseAuthor = parseAuthor; diff --git a/dist/utils/common.d.ts b/dist/utils/common.d.ts new file mode 100644 index 0000000..88b53e6 --- /dev/null +++ b/dist/utils/common.d.ts @@ -0,0 +1,10 @@ +export declare type RequiredProps = T & { + [P in K]-?: T[P]; +}; +export declare const getLongest: (words: string[]) => number; +export declare const scase: (text: string) => string; +export declare const mdLink: (lbl: string, href: string) => string; +export declare const parseName: (name: string) => { + scope: string; + packageName: string; +}; diff --git a/dist/utils/common.js b/dist/utils/common.js new file mode 100644 index 0000000..bcaf521 --- /dev/null +++ b/dist/utils/common.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseName = exports.mdLink = exports.scase = exports.getLongest = void 0; +const getLongest = (words) => Math.max(...words.map(({ length }) => length)); +exports.getLongest = getLongest; +const scase = (text) => `${text[0].toUpperCase()}${text.slice(1).toLowerCase()}`; +exports.scase = scase; +const mdLink = (lbl, href) => `[${lbl}](${href})`; +exports.mdLink = mdLink; +const parseName = (name) => { + const [, scope, packageName] = name.match(/(?:@([\w-]+)\/)?([\w-]+)/) || []; + return { scope, packageName }; +}; +exports.parseName = parseName; diff --git a/dist/utils/package.d.ts b/dist/utils/package.d.ts new file mode 100644 index 0000000..0c3a51f --- /dev/null +++ b/dist/utils/package.d.ts @@ -0,0 +1,23 @@ +export declare type PackagePerson = string | { + name: string; + email?: string; + url?: string; +}; +export declare type PackageInfo = { + author: PackagePerson; + contributors?: PackagePerson[]; + icon?: string; + license: string; + homepage: string; + name: string; + version: `${number}.${number}.${number}`; + description: string; + bugs: { + url: string; + }; + repository: { + type: "git" | "https"; + url: string; + }; +}; +export declare const getPackage: (path: string) => Promise; diff --git a/dist/utils/package.js b/dist/utils/package.js new file mode 100644 index 0000000..2e397d7 --- /dev/null +++ b/dist/utils/package.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getPackage = void 0; +const promises_1 = require("fs/promises"); +const getPackage = async (path) => { + try { + const contents = await promises_1.readFile(path, { encoding: "utf-8" }); + return JSON.parse(contents); + } + catch (error) { + return null; + } +}; +exports.getPackage = getPackage; diff --git a/dist/utils/types.d.ts b/dist/utils/types.d.ts new file mode 100644 index 0000000..f67b137 --- /dev/null +++ b/dist/utils/types.d.ts @@ -0,0 +1,3 @@ +export declare type RequiredOnly = { + [K in keyof T as T[K] extends Required[K] ? K : never]: T[K]; +}; diff --git a/dist/utils/types.js b/dist/utils/types.js new file mode 100644 index 0000000..ce03781 --- /dev/null +++ b/dist/utils/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/utils/validators.d.ts b/dist/utils/validators.d.ts new file mode 100644 index 0000000..1c69f29 --- /dev/null +++ b/dist/utils/validators.d.ts @@ -0,0 +1,12 @@ +import { PackageInfo } from "./package"; +export declare const validateMatchHeaders: (matches: string[]) => { + invalid: string[]; + status: boolean; + valid: string[]; +}; +export declare const validateRequiredHeaders: (packageInfo: PackageInfo) => { + status: boolean; + isValidVersion: boolean; + isValidHomepage: boolean; + missing: ("description" | "name" | "version" | "author" | "homepage" | "bugs" | "repository" | "license")[]; +}; diff --git a/dist/utils/validators.js b/dist/utils/validators.js new file mode 100644 index 0000000..a7838a6 --- /dev/null +++ b/dist/utils/validators.js @@ -0,0 +1,36 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.validateRequiredHeaders = exports.validateMatchHeaders = void 0; +const semver_1 = require("semver"); +const validator_1 = require("validator"); +const validateMatchHeaders = (matches) => { + const validationRegex = /^((?:https?|file|ftp|\*)(?=:\/\/)|(?:urn(?=:))):(?:\/\/)?(?:((?:\*||.+?)(?=\/|$)))?(\/\*|(?:.+?\*?)+)?|/; + const invalid = matches.filter((match) => !validationRegex.test(match)); + return { + invalid, + status: !invalid.length, + valid: matches.filter((m) => !invalid.includes(m)), + }; +}; +exports.validateMatchHeaders = validateMatchHeaders; +const validateRequiredHeaders = (packageInfo) => { + const required = [ + "author", + "name", + "homepage", + "version", + "description", + ]; + const missing = required.filter((p) => !(p in packageInfo)); + const { homepage, version } = packageInfo; + const isValidVersion = !!semver_1.valid(version); + const isValidHomepage = validator_1.default.isURL(homepage); + const status = [isValidVersion, isValidHomepage, !missing.length].reduce((a, c) => a && c); + return { + status, + isValidVersion, + isValidHomepage, + missing, + }; +}; +exports.validateRequiredHeaders = validateRequiredHeaders; diff --git a/src/generators/index.ts b/src/generators/index.ts index 930cbd8..9484114 100644 --- a/src/generators/index.ts +++ b/src/generators/index.ts @@ -59,9 +59,9 @@ export const generateGrantHeaders = < T extends CommonHeaders, U extends GrantOptions >( - grantMap: Record, - grants: U[] -) => { + grantMap: Record, + grants: U[] + ) => { const grantHeaders: HeaderEntries = grants.map((grant) => [ "grant", grantMap[grant],