This change passes in a list of file types to the line counting analysis. These are the languages for the databases being analyzed. Line count analysis is restricted to these files.
171 lines
4.1 KiB
TypeScript
171 lines
4.1 KiB
TypeScript
/**
|
|
* detect file info
|
|
*/
|
|
|
|
import * as fs from 'fs-extra';
|
|
import * as Path from 'path';
|
|
// @ts-ignore
|
|
import slash from 'slash2';
|
|
|
|
import { Languages, Regexes } from './languages';
|
|
|
|
export interface LineInfo {
|
|
total: number;
|
|
code: number;
|
|
comment: number;
|
|
}
|
|
|
|
export interface FileInfo {
|
|
name: string;
|
|
languages: string;
|
|
size: number;
|
|
lines: LineInfo;
|
|
}
|
|
|
|
const DefaultLine: LineInfo = {
|
|
total: 0,
|
|
code: 0,
|
|
comment: 0,
|
|
};
|
|
|
|
const DefaultFileInfo: FileInfo = {
|
|
name: '',
|
|
languages: '',
|
|
size: 0,
|
|
lines: DefaultLine,
|
|
};
|
|
|
|
/**
|
|
* Collect language info for a single file
|
|
*/
|
|
export class LocFile {
|
|
public path: string;
|
|
private rawPath: string;
|
|
|
|
private languages = new Languages();
|
|
|
|
/**
|
|
* Creates an instance of LocFile.
|
|
*/
|
|
constructor(rawPath: string, private debug = false) {
|
|
this.path = slash(rawPath);
|
|
this.rawPath = rawPath;
|
|
}
|
|
|
|
private filterData = (data: string, regexes: Regexes): LineInfo => {
|
|
const lines = data.split(/\n/);
|
|
let commentLength = 0;
|
|
let codeLength = lines.length;
|
|
const total = codeLength;
|
|
|
|
let inMultiLineComment = false;
|
|
lines.forEach((line) => {
|
|
|
|
let lineType = 'code';
|
|
line = line.trim();
|
|
|
|
if (inMultiLineComment) {
|
|
|
|
let noCode = true;
|
|
if (regexes.multiLineCommentClose.test(line)) {
|
|
// line contains the end of a multi-line comment
|
|
inMultiLineComment = false;
|
|
if (!regexes.multiLineCommentCloseEnd.test(line)) {
|
|
// the multiline comment does not end this line.
|
|
// there is real code on it.
|
|
noCode = false;
|
|
}
|
|
}
|
|
|
|
if (noCode) {
|
|
lineType = 'comm';
|
|
commentLength += 1;
|
|
codeLength -= 1;
|
|
}
|
|
|
|
} else if (line) {
|
|
|
|
// non-empty line
|
|
if (regexes.multiLineCommentOpen.test(line)) {
|
|
// line contains the start of a multi-line comment
|
|
// might contain some real code, but we'll let that slide
|
|
|
|
if (!regexes.multiLineCommentOpenAndClose.test(line)) {
|
|
// comment is not also closed on this line
|
|
inMultiLineComment = true;
|
|
}
|
|
|
|
if (regexes.multiLineCommentOpenStart.test(line)) {
|
|
// The comment starts the line. There is no other code on this line
|
|
commentLength += 1;
|
|
codeLength -= 1;
|
|
lineType = 'comm';
|
|
}
|
|
|
|
} else if (regexes.singleLineComment.test(line)) {
|
|
// line contains only a single line comment
|
|
commentLength += 1;
|
|
codeLength -= 1;
|
|
lineType = 'comm';
|
|
}
|
|
|
|
} else {
|
|
// empty line
|
|
codeLength -= 1;
|
|
lineType = 'empt';
|
|
}
|
|
|
|
if (this.debug) {
|
|
console.log(lineType, line)
|
|
}
|
|
});
|
|
|
|
return {
|
|
...DefaultLine,
|
|
total,
|
|
code: codeLength,
|
|
comment: commentLength,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get file info when LocFile init
|
|
*/
|
|
public async getFileInfo(data?: string): Promise<FileInfo> {
|
|
if (!(await fs.pathExists(this.rawPath))) {
|
|
throw new Error(`Error: file ${this.rawPath} does not exist.`);
|
|
}
|
|
|
|
let newData = data;
|
|
const info: FileInfo = Object.assign({}, DefaultFileInfo);
|
|
const name = this.path.split(Path.sep).pop() || '';
|
|
try {
|
|
const stat = await fs.stat(this.path);
|
|
if (!stat.isFile()) {
|
|
return info;
|
|
}
|
|
newData = data || await fs.readFile(this.path, 'utf-8');
|
|
info.name = name;
|
|
info.size = (stat && stat.size) || 0;
|
|
info.languages = this.languages.getType(this.path);
|
|
if (!info.languages) {
|
|
return info;
|
|
}
|
|
if (newData) {
|
|
const regexes = this.languages.getRegexes(info.languages);
|
|
info.lines = this.filterData(newData, regexes);
|
|
}
|
|
} catch (err) {
|
|
throw new Error('read file failed.');
|
|
}
|
|
return info;
|
|
}
|
|
|
|
public getFileInfoByContent(name: string, data: string): FileInfo {
|
|
const info: FileInfo = Object.assign({}, DefaultFileInfo);
|
|
info.name = name;
|
|
info.languages = this.languages.getType(name);
|
|
info.lines = this.filterData(data, this.languages.getRegexes(info.languages));
|
|
return info;
|
|
}
|
|
}
|