Skip to content

Commit

Permalink
fix: #128
Browse files Browse the repository at this point in the history
  • Loading branch information
AnatoleLucet committed May 21, 2020
1 parent 7621940 commit 3c33290
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 33 deletions.
35 changes: 26 additions & 9 deletions src/index/formatFileStructure/fixImports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ const getNewImportPath = (
return makeImportPath(newFilePath, absImportPath, lastUseForwardSlash);
};

const getNumOfNewChar = (a: number, b: number) => {
const numOfNewChar = b - a;

// less char than before
if (a > b) return -Math.abs(numOfNewChar);

return numOfNewChar;
};

export const fixImports = (filePaths: string[], rootOptions: RootOption[]) => {
for (const filePath of filePaths) {
logger.debug(`checking imports of "${filePath}"`);
Expand All @@ -52,25 +61,33 @@ export const fixImports = (filePaths: string[], rootOptions: RootOption[]) => {
const newFilePath = getNewFilePath(filePath, rootOptions);
const ogText = readFileSync(filePath).toString();

let newText = ogText.repeat(1);
for (const importPath of importPaths) {
const absPath = customResolve(importPath, basedir);
let newText = ogText;
let numOfNewChar = 0;

for (const _import of importPaths) {
const absPath = customResolve(_import.path, basedir);

if (absPath == null) {
logger.error(`Cannot find import ${importPath} for ${basedir}`);
logger.error(`Cannot find import ${_import.path} for ${basedir}`);
continue;
}

const newImportPath = getNewImportPath(absPath, newFilePath, rootOptions);

if (newImportPath != null && importPath !== newImportPath) {
if (newImportPath != null && _import.path !== newImportPath) {
logger.debug(
`replacing import of "${importPath}" by "${newImportPath}" in "${filePath}"`
`replacing import of "${_import.path}" by "${newImportPath}" in "${filePath}"`
);

newText = newText
.replace(`'${importPath}'`, `'${newImportPath}'`)
.replace(`"${importPath}"`, `"${newImportPath}"`);
newText = `${newText.substr(
0,
_import.start + numOfNewChar
)}${newImportPath}${newText.substring(_import.end + numOfNewChar)}`;

numOfNewChar += getNumOfNewChar(
_import.path.length,
newImportPath.length
);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/index/generateTrees/buildGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ export function buildGraph(filePaths: string[]) {
const start = path.relative(parentFolder, filePath);
totalFiles.push(start);

findImports(filePath).forEach(importPath => {
findImports(filePath).forEach(_import => {
const pathWithExtension = customResolve(
importPath,
_import.path,
path.dirname(filePath)
);

if (pathWithExtension == null) {
logger.error(`Cannot find import ${importPath} for ${filePath}`);
logger.error(`Cannot find import ${_import.path} for ${filePath}`);
return;
}

Expand Down
27 changes: 16 additions & 11 deletions src/index/shared/findImports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,34 @@ import fs from "fs";
/** Find all imports for file path. */
export function findImports(filePath: string) {
// match es5 & es6 imports
const _reImport = `(?:(?:import|from)\\s+|(?:import|require)\\s*\\()['"]((?:\\.{1,2})(?:\\/.+)?)['"]`;
const _reImport = `(?:(?:import|from)\\s+|(?:import|require)\\s*\\()\\\\?['"\`]((?:\\.{1,2})(?:\\/.+)?)\\\\?['"\`]`;
const reImport = new RegExp(_reImport, "gm");
// match one & multi line(s) comments
const reComment = /\/\*[\s\S]*?\*\/|\/\/.*/gm;
// match string which contain an import https://github.com/benawad/destiny/issues/111
const reOneLineString = new RegExp(`["'].*(${_reImport}).*["']`, "g");
const reOneLineString = new RegExp(`["'\`].*(${_reImport}).*["'\`]`, "g");
// match multi lines string which contain an import https://github.com/benawad/destiny/issues/111
const reMultiLinesString = new RegExp(`\`[^]*(${_reImport})[^]*\``, "gm");
const reMultiLinesString = new RegExp(`\`[^\`]*(${_reImport})[^\`]*\``, "gm");

const importPaths: string[] = [];
const replaceBySpaces = (match: string) => " ".repeat(match.length);

const importPaths: { path: string; start: number; end: number }[] = [];
const fileContent = fs
.readFileSync(filePath, { encoding: "utf8" })
.replace(reComment, "")
.replace(reOneLineString, "")
.replace(reMultiLinesString, "");
.replace(reComment, replaceBySpaces)
.replace(reOneLineString, replaceBySpaces)
.replace(reMultiLinesString, replaceBySpaces);

let matches;
while ((matches = reImport.exec(fileContent)) !== null) {
importPaths.push({
path: matches[1],
start: reImport.lastIndex - 1 - matches[1].length,
end: reImport.lastIndex - 1,
});

// This is necessary to avoid infinite loops with zero-width matches.
if (matches.index === reImport.lastIndex) {
reImport.lastIndex++;
}
importPaths.push(matches[1]);
if (matches.index === reImport.lastIndex) reImport.lastIndex++;
}

return importPaths;
Expand Down
39 changes: 29 additions & 10 deletions tests/findImports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import path from "path";
import fs from "fs";
import { findImports } from "../src/index/shared/findImports";

const t = (name: string, fixtureName: string, result: string[]) => {
const t = (
name: string,
fixtureName: string,
result: ReturnType<typeof findImports>
) => {
it(name, () => {
const fixturePath = path.resolve(
__dirname,
Expand All @@ -21,31 +25,46 @@ const t = (name: string, fixtureName: string, result: string[]) => {
};

describe("findImports", () => {
t("resolve es6 default import", "es6-default", ["./module"]);
t("resolve es6 default import", "es6-default", [
{ path: "./module", start: 25, end: 33 },
]);

t("resolve es6 export from module", "es6-export-module", ["./module"]);
t("resolve es6 export from module", "es6-export-module", [
{ path: "./module", start: 15, end: 23 },
]);

t("resolve es6 alias default import", "es6-alias-default", ["./module"]);
t("resolve es6 alias default import", "es6-alias-default", [
{ path: "./module", start: 25, end: 33 },
]);

t("resolve es6 named import", "es6-named", ["./module"]);
t("resolve es6 named import", "es6-named", [
{ path: "./module", start: 29, end: 37 },
]);

t("resolve es5 require", "es5-require", ["./module"]);
t("resolve es5 require", "es5-require", [
{ path: "./module", start: 9, end: 17 },
]);

t("resolve es5 require stored in variable", "es5-variable-require", [
"./module",
{ path: "./module", start: 29, end: 37 },
]);

t(
"resolve es5 multiple require stored in chained variables",
"es5-chained-variable-require",
["./module1", "./module2"]
[
{ path: "./module1", start: 61, end: 70 },
{ path: "./module2", start: 95, end: 104 },
]
);

t(
"doesn't ignore imports with a comment on the same line",
"commented-line",
["./module"]
[{ path: "./module", start: 20, end: 28 }]
);

t("doesn't match with imports in string", "import-in-string", ["./module"]);
t("doesn't match with imports in string", "import-in-string", [
{ path: "./module", start: 20, end: 28 },
]);
});

0 comments on commit 3c33290

Please sign in to comment.