Skip to content

Instantly share code, notes, and snippets.

@phenomnomnominal
Created March 11, 2019 10:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phenomnomnominal/76617fe08a20e75074e600411b6f7926 to your computer and use it in GitHub Desktop.
Save phenomnomnominal/76617fe08a20e75074e600411b6f7926 to your computer and use it in GitHub Desktop.
// Dependencies:
import { tsquery } from '@phenomnomnominal/tsquery';
import { Replacement, RuleFailure, Rules } from 'tslint';
import { SourceFile } from 'typescript';
// Constants:
const LOAD_CHILDREN_SPLIT = '#';
const LOAD_CHILDREN_VALUE_QUERY = `StringLiteral[value=/.*${LOAD_CHILDREN_SPLIT}.*/]`;
const LOAD_CHILDREN_ASSIGNMENT_QUERY = `PropertyAssignment:not(:has(Identifier[name="children"])):has(Identifier[name="loadChildren"]):has(${LOAD_CHILDREN_VALUE_QUERY})`;
const FAILURE_MESSAGE = 'Found magic `loadChildren` string. Use a function with `import` instead.';
export class Rule extends Rules.AbstractRule {
public apply(sourceFile: SourceFile): Array<RuleFailure> {
const options = this.getOptions();
const [preferAsync] = options.ruleArguments;
return tsquery(sourceFile, LOAD_CHILDREN_ASSIGNMENT_QUERY).map(result => {
const [valueNode] = tsquery(result, LOAD_CHILDREN_VALUE_QUERY);
let fix = preferAsync === 'async' ? this._asyncReplacement(valueNode.text) : this._promiseReplacement(valueNode.text);
// Try to fix indentation in replacement:
const { character } = sourceFile.getLineAndCharacterOfPosition(result.getStart());
fix = fix.replace(/\n/g, `\n${' '.repeat(character)}`);
const replacement = new Replacement(valueNode.getStart(), valueNode.getWidth(), fix);
return new RuleFailure(sourceFile, result.getStart(), result.getEnd(), FAILURE_MESSAGE, this.ruleName, replacement);
});
}
private _promiseReplacement (loadChildren: string): string {
const [path, moduleName] = this._getChunks(loadChildren);
return `() => import('${path}').then(m => m.${moduleName})`;
}
private _asyncReplacement (loadChildren: string): string {
const [path, moduleName] = this._getChunks(loadChildren);
return `async () => {
const { ${moduleName} } = await import('${path}');
return ${moduleName};
}`;
}
private _getChunks (loadChildren: string): Array<string> {
return loadChildren.split(LOAD_CHILDREN_SPLIT);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment