-
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #76 from garronej/config-assertion
test(config): improved the assertion and parsing of config
- Loading branch information
Showing
19 changed files
with
512 additions
and
410 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import * as YAML from "yaml"; | ||
import config from "."; | ||
|
||
export type ConfigFileType = | ||
| { | ||
type: "absent"; | ||
} | ||
| { | ||
// yaml is superset of json, we can treat it as yaml instead | ||
type: "js" | "yaml"; | ||
configFileBasename: string; | ||
configFileRawContent: string; | ||
}; | ||
|
||
function tryParseAsYamlCompatible(content: string) { | ||
try { | ||
return YAML.parse(content); | ||
} catch { | ||
return undefined; | ||
} | ||
} | ||
|
||
function parseConfig({ | ||
configFileBasename, | ||
configFileRawContent | ||
}: { | ||
configFileBasename: string | undefined; | ||
configFileRawContent: string | undefined; | ||
}): ConfigFileType { | ||
if ( | ||
configFileBasename === undefined || | ||
configFileRawContent === undefined || | ||
!config.supportedConfigFile.find(configFile => configFileBasename.endsWith(configFile)) | ||
) { | ||
return { | ||
type: "absent" | ||
}; | ||
} | ||
if ( | ||
(configFileBasename === ".denoifyrc" || | ||
configFileBasename.endsWith(".json") || | ||
configFileBasename.endsWith(".yaml") || | ||
configFileBasename.endsWith(".yml")) && | ||
tryParseAsYamlCompatible(configFileRawContent) | ||
) { | ||
return { | ||
type: "yaml", | ||
configFileBasename, | ||
configFileRawContent | ||
}; | ||
} | ||
if (configFileBasename.endsWith(".cjs") || configFileBasename.endsWith(".js")) { | ||
return { | ||
type: "js", | ||
configFileBasename, | ||
configFileRawContent | ||
}; | ||
} | ||
return { | ||
type: "absent" | ||
}; | ||
} | ||
|
||
export default function getFileTypeAndContent({ | ||
getConfigFileRawContent | ||
}: { | ||
getConfigFileRawContent: (configFileBasename: string) => Promise<string | undefined>; | ||
}) { | ||
return config.supportedConfigFile.reduce(async (configFileType, configFileBasename) => { | ||
if ((await configFileType).type !== "absent") { | ||
return configFileType; | ||
} | ||
const configFileRawContent = await getConfigFileRawContent(configFileBasename); | ||
if (!configFileRawContent || (configFileBasename === config.packageJson && !tryParseAsYamlCompatible(configFileRawContent)?.denoify)) { | ||
return configFileType; | ||
} | ||
return parseConfig({ | ||
configFileBasename, | ||
configFileRawContent | ||
}); | ||
}, Promise.resolve({ type: "absent" }) as Promise<ConfigFileType>); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { cosmiconfig } from "cosmiconfig"; | ||
import { parseAsDenoifyParams } from "./parseParams"; | ||
|
||
const config = (() => { | ||
const packageJson = "package.json"; | ||
return { | ||
packageJson, | ||
"supportedConfigFile": (() => { | ||
const denoify = "denoify"; | ||
const rcs = ["", ".json", ".yaml", ".yml"]; | ||
const configs = [".js", ".cjs"]; | ||
// in order of precedence | ||
return [packageJson].concat( | ||
rcs.concat(configs).map(extension => `.${denoify}rc${extension}`), | ||
configs.map(extension => `${denoify}.config${extension}`) | ||
); | ||
})(), | ||
"getDenoifyParamsWithCosmiconfig": async () => { | ||
const explorer = cosmiconfig("denoify"); | ||
const search = await explorer.search(); | ||
if (search) { | ||
console.log(`Configurations from ${search.filepath} are used`); | ||
} | ||
return parseAsDenoifyParams(search?.config ?? undefined); | ||
} | ||
} as const; | ||
})(); | ||
|
||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import * as fs from "fs"; | ||
import * as YAML from "yaml"; | ||
import { cosmiconfig } from "cosmiconfig"; | ||
import config from "."; | ||
import { ConfigFileType } from "./fileAndContent"; | ||
|
||
export type DenoifyParams = { | ||
replacer?: string; | ||
ports?: { | ||
[portName: string]: string; | ||
}; | ||
out?: string; | ||
index?: string; | ||
includes?: ( | ||
| string | ||
| { | ||
src: string; | ||
destDir?: string; | ||
destBasename?: string; | ||
} | ||
)[]; | ||
}; | ||
|
||
function parseAsStringElseUndefined(param: unknown) { | ||
return typeof param === "string" ? param : undefined; | ||
} | ||
|
||
function parseAsStringElseThrow({ param, type }: { param: unknown; type: string }) { | ||
if (typeof param === "string") { | ||
return param; | ||
} | ||
throw new Error( | ||
[ | ||
"Denoify configuration Error", | ||
`Expect ${type} to be string, got ${param} instead`, | ||
"See: https://github.com/garronej/my_dummy_npm_and_deno_module" | ||
].join("\n") | ||
); | ||
} | ||
|
||
export function parseAsDenoifyParams(denoifyParams: any): DenoifyParams | undefined { | ||
if (denoifyParams === undefined) { | ||
return undefined; | ||
} | ||
const { includes } = denoifyParams; | ||
return { | ||
"replacer": parseAsStringElseUndefined(denoifyParams.replacer), | ||
"out": parseAsStringElseUndefined(denoifyParams.out), | ||
"index": parseAsStringElseUndefined(denoifyParams.index), | ||
"includes": !Array.isArray(includes) | ||
? undefined | ||
: includes.map(elem => | ||
typeof elem === "string" | ||
? elem | ||
: { | ||
"destDir": parseAsStringElseUndefined(elem.destDir), | ||
"destBasename": parseAsStringElseUndefined(elem.destBasename), | ||
"src": parseAsStringElseThrow({ | ||
"param": elem.src, | ||
"type": "src in includes array" | ||
}) | ||
} | ||
), | ||
"ports": | ||
denoifyParams.ports !== undefined || denoifyParams.ports !== null | ||
? undefined | ||
: Object.entries(denoifyParams.ports).reduce( | ||
(prev, [portName, value]) => ({ | ||
...prev, | ||
[portName]: parseAsStringElseThrow({ | ||
"param": value, | ||
"type": "value of ports object" | ||
}) | ||
}), | ||
{} | ||
) | ||
}; | ||
} | ||
|
||
export function parseAsDenoifyConfig({ configFileType }: { configFileType: ConfigFileType }) { | ||
switch (configFileType.type) { | ||
case "absent": | ||
return undefined; | ||
case "yaml": { | ||
const parsed = YAML.parse(configFileType.configFileRawContent); | ||
return parseAsDenoifyParams(configFileType.configFileBasename !== config.packageJson ? parsed : parsed.denoify); | ||
} | ||
case "js": { | ||
const denoifyCacheDirPath = "node_modules/.cache/denoify/cacheDirPath"; | ||
if (!fs.existsSync(denoifyCacheDirPath)) { | ||
fs.mkdirSync(denoifyCacheDirPath, { | ||
"recursive": true | ||
}); | ||
} | ||
const path = `${process.cwd()}/${denoifyCacheDirPath}/config.js`; | ||
fs.writeFileSync(path, configFileType.configFileRawContent); | ||
// cosmiconfig internally uses import-fresh to parse JS config | ||
// import-fresh only support commonjs export, so we can use require | ||
return parseAsDenoifyParams(require(path)); | ||
} | ||
} | ||
} | ||
|
||
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.