Skip to content

Commit

Permalink
chore: PR remarks
Browse files Browse the repository at this point in the history
  • Loading branch information
FredericEspiau committed Dec 23, 2024
1 parent 1e5eda1 commit a7ae0cc
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 202 deletions.
55 changes: 41 additions & 14 deletions lib/util/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import { MemoryFileService } from './MemoryFileService.js';
import { findFileUsage } from './findFileUsage.js';
import { parseFile } from './parseFile.js';
import { Output } from './Output.js';
import * as Export from './export.js';
import {
WholeExportDeclarationWithFile,
isWholeExportDeclarationWithFile,
isNamedExport,
isWholeExportDeclaration,
} from './export.js';

const transform = (
source: string,
Expand Down Expand Up @@ -93,7 +98,7 @@ const createLanguageService = ({
projectRoot: string;
fileService: FileService;
}) => {
return ts.createLanguageService({
const languageService = ts.createLanguageService({
getCompilationSettings() {
return options;
},
Expand All @@ -119,6 +124,8 @@ const createLanguageService = ({
return fileService.get(name);
},
});

return languageService;
};

const updateExportDeclaration = (code: string, unused: string[]) => {
Expand Down Expand Up @@ -183,21 +190,41 @@ const getSpecifierPosition = (exportDeclaration: string) => {
/**
* Retrieves the names of the exports from a whole export declaration.
* For each whole export declaration, it will recursively get the names of the exports from the file it points to.
*
* No need to memoize this function because `parseFile` already memoizes the file parsing.
*/
const deeplyGetExportNames = ({
item,
files,
fileNames,
options,
filesAlreadyVisited = new Set<string>(),
}: {
item: Export.WholeExportDeclaration.FileFound;
item: WholeExportDeclarationWithFile;
files: Map<string, string>;
fileNames: Set<string>;
options: ts.CompilerOptions;
}): string[] => {
const filesAlreadyVisited = new Set<string>();

return innerDeeplyGetExportNames({
item,
files,
fileNames,
options,
filesAlreadyVisited,
});
};

const innerDeeplyGetExportNames = ({
item,
files,
fileNames,
options,
filesAlreadyVisited,
}: {
item: WholeExportDeclarationWithFile;
files: Map<string, string>;
fileNames: Set<string>;
options: ts.CompilerOptions;
filesAlreadyVisited?: Set<string>;
filesAlreadyVisited: Set<string>;
}): string[] => {
if (filesAlreadyVisited.has(item.file)) {
return [];
Expand All @@ -212,12 +239,10 @@ const deeplyGetExportNames = ({

const deepExportNames = parsed.exports
.filter(
(v) =>
Export.isWholeExportDeclaration(v) &&
Export.WholeExportDeclaration.isFileFound(v),
(v) => isWholeExportDeclaration(v) && isWholeExportDeclarationWithFile(v),
)
.flatMap((v) =>
deeplyGetExportNames({
innerDeeplyGetExportNames({
item: v,
files,
fileNames,
Expand All @@ -227,7 +252,7 @@ const deeplyGetExportNames = ({
);

return parsed.exports
.filter(Export.isNamedExport)
.filter(isNamedExport)
.flatMap((v) => v.name)
.concat(deepExportNames);
};
Expand Down Expand Up @@ -475,7 +500,7 @@ const processFile = ({
break;
}
case 'whole': {
if (!Export.WholeExportDeclaration.isFileFound(item)) {
if (!isWholeExportDeclarationWithFile(item)) {
// whole export is directed towards a file that is not in the project
break;
}
Expand Down Expand Up @@ -583,11 +608,13 @@ export {};\n`,
}

if (changes.length === 0) {
return {
const result = {
operation: 'edit' as const,
content: files.get(targetFile) || '',
removedExports: logs,
};

return result;
}

let content = applyTextChanges(files.get(targetFile) || '', changes);
Expand Down
179 changes: 175 additions & 4 deletions lib/util/export.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,181 @@
import ts from 'typescript';

import { NamedExport } from './export/namedExport.js';
import { WholeExportDeclaration } from './export/wholeExportDeclaration.js';
export type ClassDeclaration = {
kind: ts.SyntaxKind.ClassDeclaration;
name: string;
change: {
code: string;
isUnnamedDefaultExport?: boolean;
span: {
start: number;
length: number;
};
};
skip: boolean;
start: number;
};

export * as NamedExport from './export/namedExport.js';
export * as WholeExportDeclaration from './export/wholeExportDeclaration.js';
export type EnumDeclaration = {
kind: ts.SyntaxKind.EnumDeclaration;
name: string;
change: {
code: string;
span: {
start: number;
length: number;
};
};
skip: boolean;
start: number;
};

export type ExportAssignment = {
kind: ts.SyntaxKind.ExportAssignment;
name: 'default';
change: {
code: string;
span: {
start: number;
length: number;
};
};
skip: boolean;
start: number;
};

export type FunctionDeclaration = {
kind: ts.SyntaxKind.FunctionDeclaration;
name: string;
change: {
code: string;
isUnnamedDefaultExport?: boolean;
span: {
start: number;
length: number;
};
};
skip: boolean;
start: number;
};

export type InterfaceDeclaration = {
kind: ts.SyntaxKind.InterfaceDeclaration;
name: string;
change: {
code: string;
span: {
start: number;
length: number;
};
};
skip: boolean;
start: number;
};

export type NameExportDeclaration = {
kind: ts.SyntaxKind.ExportDeclaration;
type: 'named';
name: string[];
skip: boolean;
change: {
code: string;
span: {
start: number;
length: number;
};
};
start: number;
};

export type NamespaceExportDeclaration = {
kind: ts.SyntaxKind.ExportDeclaration;
type: 'namespace';
name: string;
start: number;
change: {
code: string;
span: {
start: number;
length: number;
};
};
};

export type TypeAliasDeclaration = {
kind: ts.SyntaxKind.TypeAliasDeclaration;
name: string;
change: {
code: string;
span: {
start: number;
length: number;
};
};
skip: boolean;
start: number;
};

export type VariableStatement = {
kind: ts.SyntaxKind.VariableStatement;
name: string[];
change: {
code: string;
span: {
start: number;
length: number;
};
};
skip: boolean;
start: number;
};

export type NamedExport =
| ClassDeclaration
| EnumDeclaration
| ExportAssignment
| FunctionDeclaration
| InterfaceDeclaration
| NameExportDeclaration
| NamespaceExportDeclaration
| TypeAliasDeclaration
| VariableStatement;

type WholeExportDeclarationBase = {
kind: ts.SyntaxKind.ExportDeclaration;
type: 'whole';
specifier: string;
start: number;
change: {
code: string;
span: {
start: number;
length: number;
};
};
};

/**
* Whole export when the file is found within the destFiles
*/
export type WholeExportDeclarationWithFile = WholeExportDeclarationBase & {
file: string;
};

/**
* Whole export when the file is not found within the destFiles, i.e. the file is not part of the project
*/
export type WholeExportDeclarationWithoutFile = WholeExportDeclarationBase & {
file: null;
};

export type WholeExportDeclaration =
| WholeExportDeclarationWithFile
| WholeExportDeclarationWithoutFile;

export const isWholeExportDeclarationWithFile = (
exportDeclaration: WholeExportDeclaration,
): exportDeclaration is WholeExportDeclarationWithFile =>
exportDeclaration.file !== null;

export type Export = NamedExport | WholeExportDeclaration;

Expand Down
Loading

0 comments on commit a7ae0cc

Please sign in to comment.