Skip to content

Commit

Permalink
Refactor: change ComponentProfile 'total' property to 'usage' (#53)
Browse files Browse the repository at this point in the history
* refactor(type): change total to usage

and remove `groups`

* refactor(scanner): add `reviseGroupedComponentSources` func

* bug(usageLocation): fix how to prepare usageLocation

* refactor(utils): remove unused code lines

in `module.utils`

* test(component): change property in test
  • Loading branch information
kittisakLS committed Nov 7, 2023
1 parent 07dc984 commit a29cc55
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 55 deletions.
5 changes: 2 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,11 @@ export interface VueComponent {
export interface ComponentProfile {
name: string;
type: ComponentSourceType;
total: number;
usage: number;
source: FileInfo & { package?: LibDependency };
deepestNested: number;
properties?: VueProperty[];
usageLocations?: VueComponent[];
groups?: any;
properties?: VueProperty[];
children?: { total: number; tags: string[]; source: string };
}

Expand Down
4 changes: 0 additions & 4 deletions src/utils/module.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export const traverseImports = (
} as ImportStatementUsage);
} else {
//mean using the import statement
//if (filePath?.includes("router.ts")) {
const { name } = path.node.value;
const found = mappedImportList.find((ele) =>
ele.importedNames.includes(name)
Expand All @@ -122,7 +121,6 @@ export const traverseImports = (
importPath: found.source,
};
}
// }
}
}
},
Expand Down Expand Up @@ -222,12 +220,10 @@ export async function getCodeConfigCompilerOptionPaths(
for (const fPath of foundConfigFiles.filter(
(ele) => !ele.includes("/node_modules/")
)) {
// logger.debug({ fPath });
try {
const result = loadConfig(fPath);
const { resultType } = result;
if ("success" === resultType) {
// logger.debug({ result }, "[Func] getCodeConfigCompilerOptionPaths");
const { absoluteBaseUrl, paths, baseUrl } = result;
pathsResult = {
...pathsResult,
Expand Down
136 changes: 92 additions & 44 deletions src/vue-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
} from "./utils/text.utils";
import { GitService } from "./utils/git.services";
import logger from "./utils/logger";
import { Dictionary } from "lodash";

type CompilerSFC = typeof import("@vue/compiler-sfc");
type BabelParser = typeof import("@babel/parser");
Expand Down Expand Up @@ -498,7 +499,7 @@ export class VueScanner implements Scanner {
if (foundSourceElem) {
foundSourceElem.rows.push(row);
} else {
// Check if the file path matchs in the `ignorePatterns` array.
// Check if the file path matches in the `ignorePatterns` array.
if (ignorePatterns.some((pattern) => source.match(pattern))) {
return;
}
Expand Down Expand Up @@ -758,7 +759,7 @@ export class VueScanner implements Scanner {
{ values: [] as ComponentProfile[], indices: [] as number[] }
);
duplicatedTagWithIndices.values.forEach((dup, i) => {
const { usageLocations, total } = dup;
const { usageLocations } = dup;
const newDetails = usageLocations?.map((e) => {
e.source = source;
return e;
Expand All @@ -776,7 +777,6 @@ export class VueScanner implements Scanner {
}
});
}
ele.total += total;
});
duplicatedTagWithIndices.indices.forEach((deleteIdx) => {
deletedIdxList.push(deleteIdx);
Expand All @@ -798,6 +798,61 @@ export class VueScanner implements Scanner {
});
}

/**
* Revises and normalizes a dictionary of grouped Vue component sources.
* This function takes a dictionary of Vue component sources and performs normalization on the keys, ensuring that components with similar names but different naming conventions are correctly merged.
* It also ensures that components with the same source and destination are merged into a single entry.
* @param groupedComponentSources - The dictionary of grouped Vue component sources.
* @returns The revised and normalized dictionary of Vue component sources.
*/
reviseGroupedComponentSources(
groupedComponentSources: Dictionary<VueComponent[]>
) {
let revisedGroupedComponentSources = Object.entries(
groupedComponentSources
).reduce(
(acc, [key, value]) => {
// Normalize the key by replacing "__" with "-"
const [tagName, sourcePath] = key.split("__");
const kebabCase = pascalCaseToKebabCase(tagName);
const pascalCase = kebabCaseToPascalCase(tagName);
const foundKey = Object.keys(acc).find((k) =>
[
`${kebabCase}__${sourcePath}`,
`${pascalCase}__${sourcePath}`,
].includes(k)
);
// Check if the normalized key exists in the merged object
if (foundKey) {
// If it exists, merge the arrays
acc[foundKey] = acc[foundKey].concat(value);
} else {
// If it doesn't exist, create a new key with the value
acc[key] = value;
}
return acc;
},
{} as Record<string, VueComponent[]>
);

return Object.entries(revisedGroupedComponentSources).reduce(
(acc, [k, v]) => {
const camelFound = v.find(
(ele) => ele.source && ele.source === ele.destination
);
if (camelFound) {
const { name } = camelFound;
const keySourceSplitted = k.split("__");
acc[`${name}__${keySourceSplitted[1]}`] = v;
} else {
acc[k] = v;
}
return acc;
},
{} as Record<string, VueComponent[]>
);
}

/**
* Removes the app directory and its contents, including subdirectories and files.
* This operation is performed forcefully and recursively.
Expand Down Expand Up @@ -1006,46 +1061,24 @@ export class VueScanner implements Scanner {
));

// Revises a grouped object of component sources by merging entries with similar keys.
const revisedGroupedComponentSources = Object.entries(
const revisedGroupedComponentSources = this.reviseGroupedComponentSources(
groupedComponentSources
).reduce(
(acc, [key, value]) => {
// Split the key into tagName and sourcePath
const [tagName, sourcePath] = key.split("__");
// Convert tagName to kebab-case and camelCase
const kebabCase = pascalCaseToKebabCase(tagName);
const pascalCase = kebabCaseToPascalCase(tagName);
// Find an existing key that matches either kebab-case or pascalCase
const foundKey = Object.keys(acc).find((k) =>
[
`${kebabCase}__${sourcePath}`,
`${pascalCase}__${sourcePath}`,
].includes(k)
);
// If a matching key is found, merge the values; otherwise, create a new entry
if (foundKey) {
acc[foundKey] = acc[foundKey].concat(value);
} else {
acc[key] = value;
}
return acc;
},
{} as Record<string, VueComponent[]>
);
// Create component profiles from grouped sources.
this.componentProfiles = Object.entries(revisedGroupedComponentSources).map(
(ele) => {
const vueComponents = ele[1];
const { name, fileInfo, source, deepestNested } = vueComponents.at(0)!;
const ownComponentFile = vueComponents.find(
(ele) => ele.source && ele.source === ele.destination
);
const { name, fileInfo, source, deepestNested } =
ownComponentFile ?? vueComponents.at(0)!;
fileInfo.path = source;
const total = vueComponents.reduce((sum, i) => {
sum += i.rows.length;
return sum;
}, 0);

return {
name,
type: existsSync(source) ? "internal" : null,
total,
usage: 0,
deepestNested,
source: fileInfo,
} as ComponentProfile;
Expand Down Expand Up @@ -1073,19 +1106,23 @@ export class VueScanner implements Scanner {
);
// Initialize the component's usageLocations property with foundUsageLocations
arr[idx].usageLocations =
foundUsageLocations.filter((ele) => ele.rows.length) ?? [];
foundUsageLocations?.filter((ele) => ele.rows.length) ?? [];
// If there's a foundImportWithUsage, add it to the component's usageLocations
if (foundImportWithUsage) {
const tmpVueComponent = {
name: "",
source:
foundImportWithUsage.sourcePath ?? foundImportWithUsage.source,
destination: foundImportWithUsage.destination,
rows: foundImportWithUsage.usage!.lines[
foundImportWithUsage.destination
],
} as VueComponent;
arr[idx].usageLocations!.push(tmpVueComponent);
const { usage } = foundImportWithUsage;
if (usage?.lines) {
Object.keys(usage.lines).forEach((destPath) => {
const rows = usage.lines[destPath];
const tmpVueComponent = {
name: "",
source:
foundImportWithUsage.sourcePath ?? foundImportWithUsage.source,
destination: destPath,
rows,
} as VueComponent;
arr[idx].usageLocations!.push(tmpVueComponent);
});
}
}
});

Expand All @@ -1096,6 +1133,17 @@ export class VueScanner implements Scanner {
this.componentProfiles = this.removeDuplicateComponents(
this.componentProfiles
);

// revise component usage
this.componentProfiles.forEach((comp) => {
const { usageLocations } = comp;
const totalUsage =
usageLocations?.reduce((sum, i) => {
sum += i.rows.length;
return sum;
}, 0) ?? 0;
comp.usage = totalUsage;
});
this.mapComponentProfileProps(filePathToProperties);
if (existsSync(join(this.scanPath, ".git"))) {
// Use Git Scan
Expand Down
6 changes: 2 additions & 4 deletions tests/analyze-component-files.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ describe("Remove duplicate components", () => {
componentProfiles.push({
name: "Button",
type: "internal",
total: 0,
usage: 0,
deepestNested: 0,
source: {
path: "C:/projects/berryjam-cli/public/Components/Header.js",
Expand All @@ -221,15 +221,14 @@ describe("Remove duplicate components", () => {
},
properties: [],
usageLocations: [],
groups: [],
children: { total: 1, tags: ["Button"], source: "" },
});
// Push 2nd object
componentProfiles.push({
name: "Button",
type: "internal",
deepestNested: 0,
total: 0,
usage: 0,
source: {
path: "C:/projects/berryjam-cli/public/Components/Header.js",
property: {
Expand All @@ -242,7 +241,6 @@ describe("Remove duplicate components", () => {
},
properties: [],
usageLocations: [],
groups: [],
children: { total: 1, tags: ["Button"], source: "" },
});

Expand Down

0 comments on commit a29cc55

Please sign in to comment.