denoify
Version:
For NPM module authors that would like to support Deno but do not want to write and maintain a port.
139 lines (126 loc) • 5.18 kB
text/typescript
import * as fs from "fs";
import { cosmiconfig } from "cosmiconfig";
import config from ".";
import type { ConfigFileType } from "./fileAndContent";
import { join as pathJoin, dirname as pathDirname } from "path";
const guardAsOptionalString = (string: unknown) => (typeof string === "string" ? string : undefined);
const guardAsString = (param: { string: unknown; errorMessage: string }) => {
if (typeof param.string === "string") {
return param.string;
}
throw new Error(param.errorMessage);
};
export type DenoifyParams = {
replacer?: string;
ports?: {
[portName: string]: string;
};
out?: string;
index?: string;
includes?: (
| string
| {
src: string;
destDir?: string;
destBasename?: string;
}
)[];
};
export function parseAsDenoifyParams(denoifyParams: any): DenoifyParams | undefined {
if (denoifyParams === undefined) {
return undefined;
}
const generateErrorMessage = ({ name, type, param }: { name: string; type: string; param: unknown }) =>
[
"Denoify configuration Error",
`Expect ${name} to be ${type}, got ${param} instead`,
"See: https://github.com/garronej/my_dummy_npm_and_deno_module"
].join("\n");
const { includes } = denoifyParams;
return {
"replacer": guardAsOptionalString(denoifyParams.replacer),
"out": guardAsOptionalString(denoifyParams.out),
"index": guardAsOptionalString(denoifyParams.index),
"includes": !Array.isArray(includes)
? undefined
: includes.map(element => {
const result = guardAsOptionalString(element);
if (result !== undefined) {
return result;
}
if (typeof element !== "object") {
throw new Error(
generateErrorMessage({
"param": includes,
"name": "element in includes",
"type": "object with type: { destDir: string?, destBasename: string?, src: string }"
})
);
}
return {
"destDir": guardAsOptionalString(element.destDir),
"destBasename": guardAsOptionalString(element.destBasename),
"src": guardAsString({
string: element.src,
errorMessage: generateErrorMessage({
"type": "string",
"param": element.src,
"name": "src in includes array"
})
})
};
}),
"ports":
denoifyParams.ports === undefined || denoifyParams.ports === null
? undefined
: Object.entries(denoifyParams.ports).reduce(
(prev, [portName, string]) => ({
...prev,
[portName]: guardAsString({
string,
errorMessage: generateErrorMessage({
"param": string,
"type": "string",
"name": "value of ports object"
})
})
}),
{}
)
};
}
export function parseAsDenoifyConfig({ configFileType }: { configFileType: ConfigFileType }) {
switch (configFileType.type) {
case "absent":
return undefined;
case "json": {
const parsed = JSON.parse(configFileType.configFileRawContent);
return parseAsDenoifyParams(configFileType.configFileBasename !== config.packageJson ? parsed : parsed.denoify);
}
case "js": {
const cacheFilePath = pathJoin(process.cwd(), "node_modules", ".cache", "denoify", "cacheDirPath", "config.js");
{
const dirPath = pathDirname(cacheFilePath);
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, {
"recursive": true
});
}
}
fs.writeFileSync(cacheFilePath, configFileType.configFileRawContent);
// cosmiconfig internally uses import-fresh to parse JS config
// import-fresh only support commonjs export, so we can use require
const denoifyParams = parseAsDenoifyParams(require(cacheFilePath));
fs.rmSync(cacheFilePath, { "force": true });
return denoifyParams;
}
}
}
export async function getDenoifyParamsWithCosmiconfig() {
const explorer = cosmiconfig("denoify");
const search = await explorer.search();
if (search) {
console.log(`Configurations from ${search.filepath} are used`);
}
return parseAsDenoifyParams(search?.config ?? undefined);
}