As already known, dependent
relies heavily on its parsing capabilities to support multitude of files. The currently supported files are documented in the readme file. Other than any supported files, dependent
cannot parse those files correctly and any attempt to parse those files will produce an error.
If you feel that a particular file extension should be supported by dependent
, you can submit an issue ...or you can contribute to add language support directly to dependent
!
For starters, please read the contribution guidelines until you have successfully setup dependent
in your local machine.
All parsers are stored in src/parser/<ext>.ts
where <ext>
is the supported file extension (e.g: ts.ts
is a parser for TypeScript files). All parsers must be provided as a TypeScript file.
All parsers must export at least one function which satisfies the following TypeScript type definition.
export type FileParser = (
content: string,
dependency: string,
globs: string[],
) => number[];
Where content
is the content of an analyzed file and dependency
is the name of dependency which will be checked. Full details of the type can be seen in types.ts
.
If the parsed content
is structured in ESTree Node
or similar data structure, it's preferable that a different function is used to parse the Node
itself rather than bundling it in a single exported function. For example:
export function parseNode(
sourceNode: Node,
dependency: string,
): number[] {
const lines: number[] = [];
simple(sourceNode, {
ImportExpression(node: Node) {
const importExpr = node as unknown as ImportExpression;
if (
importExpr.source.type === 'Literal' &&
importExpr.source.value === dependency
) {
lines.push((node.loc as SourceLocation).start.line);
}
},
ImportDeclaration(node: Node) {
const importDec = node as unknown as ImportDeclaration;
if (
importDec.source.type === 'Literal' &&
importDec.source.value === dependency
) {
lines.push((node.loc as SourceLocation).start.line);
}
},
CallExpression(node: Node) {
const callExpr = node as unknown as CallExpression;
if (
callExpr.callee.type === 'Identifier' &&
callExpr.callee.name === 'require' &&
callExpr.arguments[0].type === 'Literal' &&
callExpr.arguments[0].value === dependency
) {
lines.push((node.loc as SourceLocation).start.line);
}
},
});
return lines;
}
export function getXXXImportLines(
content: string,
dependency: string,
): number[] {
const node: Node = parse(content, {
ecmaVersion: 'latest',
locations: true,
allowHashBang: true,
sourceType: 'module',
});
return parseNode(node, dependency);
}
See all examples of parser here.
After the main function is exported, you must register it on index.ts
, specifically on PARSER_MAP
, else the parser cannot be recognized by dependent
. PARSER_MAP
is a key-value map that stores file extension to their respective parser function. The following example shows an example of registering js
files to the getXXXModulesImportLines
from the function above.
export const PARSER_MAP: Record<string, FileParser> = {
// ...
js: getESModulesImportLines,
// ...
};
In the future, it might be possible for
dependent
to automatically register parsers by itself.
In order to guarantee the correctness of a parser, a unit test must be provided for each supported parsers. All tests must be provided as a TypeScript file and will be executed by vitest
with following command
pnpm run test
See the test example for how to structure a decent test for a parser.
Please make sure that all tests must pass before submitting a pull request. Failed to comply to this rule will cause your pull request to be rejected.