fcis 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.plans/001-fcis-analyzer.md +832 -0
- package/.plans/002-fcis-analyzer-improvements.md +205 -0
- package/README.md +272 -0
- package/TECHNICAL.md +386 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1836 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +709 -0
- package/dist/index.js +1845 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
- package/pnpm-workspace.yaml +0 -0
- package/src/analyzer.ts +266 -0
- package/src/classification/classifier.ts +156 -0
- package/src/classification/derive-status.ts +171 -0
- package/src/classification/quality-scorer.ts +481 -0
- package/src/cli.ts +286 -0
- package/src/detection/detect-markers.ts +480 -0
- package/src/detection/markers.ts +332 -0
- package/src/extraction/extract-functions.ts +570 -0
- package/src/extraction/extractor.ts +188 -0
- package/src/index.ts +111 -0
- package/src/reporting/report-console.ts +416 -0
- package/src/reporting/report-json.ts +232 -0
- package/src/scoring/scorer.ts +504 -0
- package/src/types.ts +248 -0
- package/tests/classifier.test.ts +480 -0
- package/tests/derive-status.test.ts +464 -0
- package/tests/detect-markers.test.ts +639 -0
- package/tests/extractor.test.ts +155 -0
- package/tests/integration.test.ts +706 -0
- package/tests/quality-scorer.test.ts +650 -0
- package/tests/scorer.test.ts +768 -0
- package/tsconfig.json +34 -0
- package/tsup.config.ts +17 -0
- package/vendor/ts-morph/.editorconfig +10 -0
- package/vendor/ts-morph/.gitattributes +11 -0
- package/vendor/ts-morph/.github/CODE_OF_CONDUCT.md +77 -0
- package/vendor/ts-morph/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/vendor/ts-morph/.github/ISSUE_TEMPLATE/custom.md +4 -0
- package/vendor/ts-morph/.github/ISSUE_TEMPLATE/feature_request.md +18 -0
- package/vendor/ts-morph/.github/workflows/ci.yml +50 -0
- package/vendor/ts-morph/.github/workflows/publish.yml +53 -0
- package/vendor/ts-morph/.vscode/settings.json +10 -0
- package/vendor/ts-morph/CONTRIBUTING.md +23 -0
- package/vendor/ts-morph/DEVELOPMENT.md +32 -0
- package/vendor/ts-morph/LICENSE +21 -0
- package/vendor/ts-morph/deno.json +8 -0
- package/vendor/ts-morph/deno.lock +1233 -0
- package/vendor/ts-morph/docs/CNAME +1 -0
- package/vendor/ts-morph/docs/Gemfile +2 -0
- package/vendor/ts-morph/docs/_config.yml +5 -0
- package/vendor/ts-morph/docs/_layouts/default.html +159 -0
- package/vendor/ts-morph/docs/_script-templates/main.ts +116 -0
- package/vendor/ts-morph/docs/assets/css/style.scss +212 -0
- package/vendor/ts-morph/docs/details/ambient.md +38 -0
- package/vendor/ts-morph/docs/details/async.md +31 -0
- package/vendor/ts-morph/docs/details/classes.md +314 -0
- package/vendor/ts-morph/docs/details/comment-ranges.md +7 -0
- package/vendor/ts-morph/docs/details/comments.md +122 -0
- package/vendor/ts-morph/docs/details/decorators.md +119 -0
- package/vendor/ts-morph/docs/details/documentation.md +73 -0
- package/vendor/ts-morph/docs/details/enums.md +117 -0
- package/vendor/ts-morph/docs/details/exports.md +308 -0
- package/vendor/ts-morph/docs/details/expressions.md +46 -0
- package/vendor/ts-morph/docs/details/functions.md +150 -0
- package/vendor/ts-morph/docs/details/generators.md +27 -0
- package/vendor/ts-morph/docs/details/identifiers.md +79 -0
- package/vendor/ts-morph/docs/details/imports.md +191 -0
- package/vendor/ts-morph/docs/details/index.md +52 -0
- package/vendor/ts-morph/docs/details/initializers.md +40 -0
- package/vendor/ts-morph/docs/details/interfaces.md +218 -0
- package/vendor/ts-morph/docs/details/literals.md +20 -0
- package/vendor/ts-morph/docs/details/modifiers.md +38 -0
- package/vendor/ts-morph/docs/details/modules.md +113 -0
- package/vendor/ts-morph/docs/details/namespaces.md +7 -0
- package/vendor/ts-morph/docs/details/object-literal-expressions.md +106 -0
- package/vendor/ts-morph/docs/details/parameters.md +64 -0
- package/vendor/ts-morph/docs/details/signatures.md +41 -0
- package/vendor/ts-morph/docs/details/source-files.md +292 -0
- package/vendor/ts-morph/docs/details/type-aliases.md +34 -0
- package/vendor/ts-morph/docs/details/type-parameters.md +72 -0
- package/vendor/ts-morph/docs/details/types.md +254 -0
- package/vendor/ts-morph/docs/details/variables.md +110 -0
- package/vendor/ts-morph/docs/emitting.md +151 -0
- package/vendor/ts-morph/docs/index.md +25 -0
- package/vendor/ts-morph/docs/manipulation/code-writer.md +20 -0
- package/vendor/ts-morph/docs/manipulation/formatting.md +76 -0
- package/vendor/ts-morph/docs/manipulation/index.md +136 -0
- package/vendor/ts-morph/docs/manipulation/order.md +14 -0
- package/vendor/ts-morph/docs/manipulation/performance.md +222 -0
- package/vendor/ts-morph/docs/manipulation/removing.md +31 -0
- package/vendor/ts-morph/docs/manipulation/renaming.md +106 -0
- package/vendor/ts-morph/docs/manipulation/settings.md +76 -0
- package/vendor/ts-morph/docs/manipulation/structures.md +117 -0
- package/vendor/ts-morph/docs/manipulation/transforms.md +84 -0
- package/vendor/ts-morph/docs/metrics/performance.json +4 -0
- package/vendor/ts-morph/docs/navigation/ambient-modules.md +22 -0
- package/vendor/ts-morph/docs/navigation/compiler-nodes.md +82 -0
- package/vendor/ts-morph/docs/navigation/directories.md +287 -0
- package/vendor/ts-morph/docs/navigation/example.md +50 -0
- package/vendor/ts-morph/docs/navigation/finding-references.md +53 -0
- package/vendor/ts-morph/docs/navigation/getting-source-files.md +59 -0
- package/vendor/ts-morph/docs/navigation/images/getChildrenVsForEachChild.gif +0 -0
- package/vendor/ts-morph/docs/navigation/index.md +94 -0
- package/vendor/ts-morph/docs/navigation/language-service.md +23 -0
- package/vendor/ts-morph/docs/navigation/program.md +25 -0
- package/vendor/ts-morph/docs/navigation/type-checker.md +33 -0
- package/vendor/ts-morph/docs/setup/adding-source-files.md +145 -0
- package/vendor/ts-morph/docs/setup/ast-viewers.md +46 -0
- package/vendor/ts-morph/docs/setup/diagnostics.md +109 -0
- package/vendor/ts-morph/docs/setup/file-system.md +106 -0
- package/vendor/ts-morph/docs/setup/images/atom-ast.png +0 -0
- package/vendor/ts-morph/docs/setup/images/atom-ast_small.png +0 -0
- package/vendor/ts-morph/docs/setup/images/atom-command-palette.png +0 -0
- package/vendor/ts-morph/docs/setup/images/atom-file.png +0 -0
- package/vendor/ts-morph/docs/setup/images/ts-ast-viewer.png +0 -0
- package/vendor/ts-morph/docs/setup/index.md +94 -0
- package/vendor/ts-morph/docs/utilities.md +55 -0
- package/vendor/ts-morph/dprint.json +23 -0
- package/vendor/ts-morph/package.json +30 -0
- package/vendor/ts-morph/packages/bootstrap/LICENSE +21 -0
- package/vendor/ts-morph/packages/bootstrap/lib/ts-morph-bootstrap.d.ts +397 -0
- package/vendor/ts-morph/packages/bootstrap/package.json +46 -0
- package/vendor/ts-morph/packages/bootstrap/readme.md +200 -0
- package/vendor/ts-morph/packages/common/LICENSE +21 -0
- package/vendor/ts-morph/packages/common/lib/ts-morph-common.d.ts +1082 -0
- package/vendor/ts-morph/packages/common/lib/typescript.d.ts +11439 -0
- package/vendor/ts-morph/packages/common/package.json +65 -0
- package/vendor/ts-morph/packages/common/readme.md +5 -0
- package/vendor/ts-morph/packages/scripts/changeTypeScriptVersion.ts +28 -0
- package/vendor/ts-morph/packages/scripts/createDeclarationProject.ts +47 -0
- package/vendor/ts-morph/packages/scripts/deps.ts +2 -0
- package/vendor/ts-morph/packages/scripts/execScript.ts +31 -0
- package/vendor/ts-morph/packages/scripts/folders.ts +11 -0
- package/vendor/ts-morph/packages/scripts/getDevCompilerVersions.ts +19 -0
- package/vendor/ts-morph/packages/scripts/mod.ts +7 -0
- package/vendor/ts-morph/packages/scripts/utils/Memoize.ts +36 -0
- package/vendor/ts-morph/packages/scripts/utils/forEachTypeText.ts +23 -0
- package/vendor/ts-morph/packages/scripts/utils/makeConstructorsPrivate.ts +26 -0
- package/vendor/ts-morph/packages/scripts/utils/mod.ts +4 -0
- package/vendor/ts-morph/packages/scripts/utils/printDiagnostics.ts +10 -0
- package/vendor/ts-morph/packages/ts-morph/LICENSE +21 -0
- package/vendor/ts-morph/packages/ts-morph/lib/ts-morph.d.ts +11198 -0
- package/vendor/ts-morph/packages/ts-morph/package.json +78 -0
- package/vendor/ts-morph/packages/ts-morph/readme.md +111 -0
- package/vendor/ts-morph/readme.md +14 -0
- package/vendor/ts-morph/rfcs/README.md +13 -0
- package/vendor/ts-morph/rfcs/RFC-0001 - Inserting Into Statements Handling Comments.md +181 -0
- package/vendor/ts-morph/tsconfig.common.json +17 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Manipulating Source Files
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Manipulating Source Files
|
|
6
|
+
|
|
7
|
+
Most information about manipulation can be found in the [Details](../details) section. This section only contains general information about manipulation.
|
|
8
|
+
|
|
9
|
+
### Saving Changes
|
|
10
|
+
|
|
11
|
+
All moves, copies, and deletes won't be propagated to the underlying file system until `save()` is called on the main `project` object.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Project } from "ts-morph";
|
|
15
|
+
|
|
16
|
+
const project = new Project();
|
|
17
|
+
|
|
18
|
+
// ...lots of code here that manipulates, copies, moves, and deletes files...
|
|
19
|
+
|
|
20
|
+
// when you're all done, call this and it will save everything to the file system
|
|
21
|
+
await project.save();
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The above is recommended because it means if your code errors halfway through, the files won't be in a halfway state. However, there's always a way to save, move, copy, and delete while immediately having these changes happen on the underlying file system. For example:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// or use the synchronous alternatives (ex. saveSync())
|
|
28
|
+
await sourceFile.save();
|
|
29
|
+
await sourceFile.deleteImmediately();
|
|
30
|
+
await sourceFile.copyImmediately("copiedFile.ts");
|
|
31
|
+
await sourceFile.moveImmediately("movedFile.ts");
|
|
32
|
+
|
|
33
|
+
await directory.save();
|
|
34
|
+
await directory.deleteImmediately();
|
|
35
|
+
await directory.copyImmediately("CopiedDir");
|
|
36
|
+
await directory.moveImmediately("MovedDir");
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Replacing any node with new text
|
|
40
|
+
|
|
41
|
+
Use the `.replaceWithText(...)` method that exists on any node.
|
|
42
|
+
|
|
43
|
+
This will replace the text from the `Node#getStart(true)` position (start position with js docs) to `Node#getEnd()`. Use `Node#getText(true)` to get all the text that will be replaced.
|
|
44
|
+
|
|
45
|
+
#### Example
|
|
46
|
+
|
|
47
|
+
Given the following code:
|
|
48
|
+
|
|
49
|
+
```ts setup: let Some: any;
|
|
50
|
+
let myVariable = Some.Property.Access.Expression;
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
You can replace the property access expression with new text by doing the following:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const originalInitializer = sourceFile.getVariableDeclarations()[0].getInitializerOrThrow();
|
|
57
|
+
const newInitializer = originalInitializer.replaceWithText("MyReference");
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That will make the source file hold the following text:
|
|
61
|
+
|
|
62
|
+
```ts setup: let MyReference: any;
|
|
63
|
+
let myVariable = MyReference;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Note that `originalInitializer` will be forgotten after calling `.replaceWithText(...)` on it—an error will be thrown if you try to use it.
|
|
67
|
+
You will have to use the new node returned by that method.
|
|
68
|
+
|
|
69
|
+
### Adding, inserting, and removing statements
|
|
70
|
+
|
|
71
|
+
Statements can be added, inserted, or removed from nodes with a body (ex. functions, methods, namespaces, source files).
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// add statements
|
|
75
|
+
const statements = sourceFile.addStatements("console.log(5);\nconsole.log(6);");
|
|
76
|
+
// insert statements (index is the child index to insert at)
|
|
77
|
+
const statements = sourceFile.insertStatements(3, "console.log(5);\nconsole.log(6);");
|
|
78
|
+
// remove statements
|
|
79
|
+
sourceFile.removeStatements([1, 3]); // removes statements from index 1 to 3
|
|
80
|
+
sourceFile.removeStatement(1); // removes statement at index 1
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
When adding or inserting, you can also write using a [code writer](code-writer):
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
functionDeclaration.addStatements(writer => {
|
|
87
|
+
writer.write("if (true)").block(() => {
|
|
88
|
+
writer.write("something;");
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Inserting, replacing, and removing any text
|
|
94
|
+
|
|
95
|
+
In some scenarios, a simple to use API might not have been implemented. If you find that's the case, open an issue on GitHub.
|
|
96
|
+
|
|
97
|
+
In the meantime, you can insert, replace, and remove text using the following methods, but _generally you will want to avoid using these if possible_:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
// insert text
|
|
101
|
+
sourceFile.insertText(0, writer => writer.writeLine("// some comment")); // or provide a string
|
|
102
|
+
// replace text
|
|
103
|
+
sourceFile.replaceText([3, 7], "a"); // "// a comment\n"
|
|
104
|
+
// remove text
|
|
105
|
+
sourceFile.removeText(sourceFile.getPos(), sourceFile.getEnd());
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
These methods are also available on any node that has a body (functions, classes, enums, etc.)
|
|
109
|
+
|
|
110
|
+
#### **Warning**
|
|
111
|
+
|
|
112
|
+
If you use `insertText`, `replaceText`, or `removeText`, all previously navigated descendants of the node will be forgotten and not be available for use—an error will be thrown
|
|
113
|
+
if you try to use them. You will have to renavigate to those nodes.
|
|
114
|
+
|
|
115
|
+
For example:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
let classDeclaration = sourceFile.addClass({ name: "MyClass" });
|
|
119
|
+
sourceFile.insertText(0, "// some comment\n");
|
|
120
|
+
|
|
121
|
+
// this will throw...
|
|
122
|
+
classDeclaration.getInstanceProperties();
|
|
123
|
+
|
|
124
|
+
// you'll need to get the reference again:
|
|
125
|
+
classDeclaration = sourceFile.getClass("MyClass")!;
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Code Fixes
|
|
129
|
+
|
|
130
|
+
There are a variety of useful code fixes and refactors such as:
|
|
131
|
+
|
|
132
|
+
- `SourceFile#organizeImports()`
|
|
133
|
+
- `SourceFile#fixMissingImports()`
|
|
134
|
+
- `SourceFile#fixUnusedIdentifiers()`
|
|
135
|
+
|
|
136
|
+
Check more details on the [source files details page](../details/source-files).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Order
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Order
|
|
6
|
+
|
|
7
|
+
Change the order of certain nodes using the `.setOrder(newIndex: number)` method.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const interfaceDeclaration = sourceFile.getInterfaceOrThrow("MyInterface");
|
|
11
|
+
interfaceDeclaration.setOrder(2);
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Notice: Right now this is not supported on comma separated nodes. See [Issue #44](https://github.com/dsherret/ts-morph/issues/44) for more information.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Performance
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Performance
|
|
6
|
+
|
|
7
|
+
There's a lot of opportunity for performance improvements. The library originally started off favouring correctness, but it's now starting to switch to improving performance.
|
|
8
|
+
|
|
9
|
+
[View Issues](https://github.com/dsherret/ts-morph/labels/performance)
|
|
10
|
+
|
|
11
|
+
### Manipulations are slow...
|
|
12
|
+
|
|
13
|
+
Right now with every manipulation the following occurs:
|
|
14
|
+
|
|
15
|
+
1. The file text is updated.
|
|
16
|
+
2. The new text is parsed and a new AST is created using the compiler API.
|
|
17
|
+
3. The previously wrapped nodes are backfilled with new compiler nodes.
|
|
18
|
+
|
|
19
|
+
This might not be too bad when working with small to medium sized files, but large files may take a bit of time. If you find it's too slow, then I recommend reading the performance tips below.
|
|
20
|
+
|
|
21
|
+
Note: I'm working on eliminating the need to do a complete parse of the source file between manipulations. Once implemented these performance tips won't be necessary.
|
|
22
|
+
|
|
23
|
+
### Performance Tip: Work With Structures Instead
|
|
24
|
+
|
|
25
|
+
Structures are simplified ASTs. You can get a huge performance improvement by working with structures as much as possible. This is especially useful to do if you are code generating.
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// this code will get a structure from declarations.ts, make all the descendants not be exported,
|
|
31
|
+
// then create a new file called private.ts from that structure
|
|
32
|
+
import { forEachStructureChild, SourceFileStructure, StructureKind, Structures, Structures } from "ts-morph";
|
|
33
|
+
|
|
34
|
+
const project = new Project({ tsConfigFilePath: "tsconfig.json" });
|
|
35
|
+
const classesFile = project.getSourceFileOrThrow("declarations.ts");
|
|
36
|
+
const classesFileStructure = classesFile.getStructure();
|
|
37
|
+
|
|
38
|
+
removeExports(classesFileStructure);
|
|
39
|
+
|
|
40
|
+
project.createSourceFile("private.ts", classesFileStructure);
|
|
41
|
+
|
|
42
|
+
function removeExports(structure: Structures) {
|
|
43
|
+
forEachStructureChild(structure, removeExports);
|
|
44
|
+
|
|
45
|
+
if (Structure.isExportable(structure))
|
|
46
|
+
structure.isExported = false;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Read more in [structures](structures.md).
|
|
51
|
+
|
|
52
|
+
### Performance Tip: Batch operations
|
|
53
|
+
|
|
54
|
+
You can reduce the amount of parsing that needs to happen by batching operations.
|
|
55
|
+
|
|
56
|
+
For example, instead of writing code like this:
|
|
57
|
+
|
|
58
|
+
```ts setup: const classStructures: ClassDeclarationStructure[];
|
|
59
|
+
for (const classStructure of classStructures)
|
|
60
|
+
sourceFile.addClass(classStructure);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Write this instead:
|
|
64
|
+
|
|
65
|
+
```ts setup: const classStructures: ClassDeclarationStructure[];
|
|
66
|
+
sourceFile.addClasses(classStructures);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Performance Tip: Analyze then Manipulate
|
|
70
|
+
|
|
71
|
+
If the code analysis is using types, symbols type checker, or program, then a large performance improvement can be gained by doing an initial analysis of the code first, then afterwards carrying out the manipulations.
|
|
72
|
+
|
|
73
|
+
For example, given the following code:
|
|
74
|
+
|
|
75
|
+
```ts setup: const sourceFiles: SourceFile[]; const someCheckOnSymbol: any;
|
|
76
|
+
for (const sourceFile of sourceFiles) {
|
|
77
|
+
for (const classDec of sourceFile.getClasses()) {
|
|
78
|
+
if (someCheckOnSymbol(classDec.getSymbolOrThrow()))
|
|
79
|
+
classDec.remove();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Write it this way instead:
|
|
85
|
+
|
|
86
|
+
```ts setup: const sourceFiles: SourceFile[]; const someCheckOnSymbol: any;
|
|
87
|
+
for (const classDec of getClassesToRemove())
|
|
88
|
+
classDec.remove();
|
|
89
|
+
|
|
90
|
+
function getClassesToRemove() {
|
|
91
|
+
const classesToRemove: ClassDeclaration[] = [];
|
|
92
|
+
|
|
93
|
+
for (const sourceFile of sourceFiles) {
|
|
94
|
+
for (const classDec of sourceFile.getClasses()) {
|
|
95
|
+
if (someCheckOnSymbol(classDec.getSymbolOrThrow()))
|
|
96
|
+
classesToRemove.push(classDec);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return classesToRemove;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This is because the program is reset between manipulations.
|
|
105
|
+
|
|
106
|
+
### Tracking Nodes - Overview
|
|
107
|
+
|
|
108
|
+
This library makes manipulations easy for you by keeping track of how the underlying syntax tree changes between manipulations.
|
|
109
|
+
|
|
110
|
+
Behind the scenes, when you manipulate the AST:
|
|
111
|
+
|
|
112
|
+
1. A new source file is created using the TypeScript compiler.
|
|
113
|
+
2. The previously navigated nodes have their underlying compiler nodes replaced with the new compiler nodes.
|
|
114
|
+
|
|
115
|
+
It's why you can do this:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// sourcefile contains: interface Person { name: string; }
|
|
119
|
+
const personInterface = sourceFile.getInterfaceOrThrow("Person");
|
|
120
|
+
const nameProperty = personInterface.getPropertyOrThrow("name");
|
|
121
|
+
nameProperty.setType("number");
|
|
122
|
+
nameProperty.getText(); // "name: number;"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Instead of having to renavigate the tree after each manipulation:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
// thankfully the library does not work this way
|
|
129
|
+
let personInterface = sourceFile.getInterfaceOrThrow("Person");
|
|
130
|
+
let nameProperty = personInterface.getPropertyOrThrow("name");
|
|
131
|
+
nameProperty.setType("number");
|
|
132
|
+
nameProperty.getText(); // "name: string;"
|
|
133
|
+
personInterface = sourceFile.getInterfaceOrThrow("Person");
|
|
134
|
+
nameProperty = personInterface.getPropertyOrThrow("name");
|
|
135
|
+
nameProperty.getText(); // "name: number;"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
When thinking about performance, the key point here is that if you have a lot of previously navigated nodes and a very large file, then manipulation might start to become sluggish.
|
|
139
|
+
|
|
140
|
+
#### Forgetting Nodes (Advanced)
|
|
141
|
+
|
|
142
|
+
The main way to improve performance when manipulating, is to "forget" a node when you're done with it.
|
|
143
|
+
|
|
144
|
+
```ts setup: let personInterface: InterfaceDeclaration;
|
|
145
|
+
personInterface.forget();
|
|
146
|
+
|
|
147
|
+
// or to only forget a node's descendants that are currently in the wrapped cache
|
|
148
|
+
sourceFile.forgetDescendants();
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
That will stop tracking the node and all its previously navigated descendants (ex. in this case, `nameProperty` as well).
|
|
152
|
+
It won't be updated when manipulation happens again. Note that after doing this, the node will throw an error if one of its properties or methods is accessed.
|
|
153
|
+
|
|
154
|
+
#### Forget Blocks (Advanced)
|
|
155
|
+
|
|
156
|
+
It's possible to make sure all created nodes within a block are forgotten:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { ClassDeclaration, InterfaceDeclaration, ModuleDeclaration, Project } from "ts-morph";
|
|
160
|
+
|
|
161
|
+
const project = new Project();
|
|
162
|
+
const text = "namespace Namespace { interface Interface {} class Class {} }";
|
|
163
|
+
const sourceFile = project.createSourceFile("file.ts", text);
|
|
164
|
+
|
|
165
|
+
let moduleDeclaration: ModuleDeclaration;
|
|
166
|
+
let interfaceDeclaration: InterfaceDeclaration;
|
|
167
|
+
let classDeclaration: ClassDeclaration;
|
|
168
|
+
|
|
169
|
+
project.forgetNodesCreatedInBlock(remember => {
|
|
170
|
+
moduleDeclaration = sourceFile.getModuleOrThrow("Namespace");
|
|
171
|
+
interfaceDeclaration = moduleDeclaration.getInterfaceOrThrow("Interface");
|
|
172
|
+
classDeclaration = moduleDeclaration.getClassOrThrow("Class");
|
|
173
|
+
|
|
174
|
+
// you can mark nodes to remember outside the scope of this block...
|
|
175
|
+
// this will remember the specified node and all its ancestors
|
|
176
|
+
remember(interfaceDeclaration); // or pass in multiple nodes
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
moduleDeclaration.getText(); // ok, child was implicitly marked to remember
|
|
180
|
+
interfaceDeclaration.getText(); // ok, was explicitly marked to remember
|
|
181
|
+
classDeclaration.getText(); // throws, was forgotten
|
|
182
|
+
|
|
183
|
+
// alternatively, return the node to remember it
|
|
184
|
+
const node = project.forgetNodesCreatedInBlock(() => {
|
|
185
|
+
const classDec = sourceFile.getClassOrThrow("MyClass");
|
|
186
|
+
// ...do a lot of stuff...
|
|
187
|
+
return classDec;
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
node.getText(); // ok
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Also, do not be concerned about nesting forget blocks. That is perfectly fine to do:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
project.forgetNodesCreatedInBlock(() => {
|
|
197
|
+
moduleDeclaration = sourceFile.getModuleOrThrow("Namespace");
|
|
198
|
+
interfaceDeclaration = moduleDeclaration.getInterfaceOrThrow("Interface");
|
|
199
|
+
|
|
200
|
+
project.forgetNodesCreatedInBlock(remember => {
|
|
201
|
+
classDeclaration = moduleDeclaration.getClassOrThrow("Class");
|
|
202
|
+
remember(moduleDeclaration);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
classDeclaration.getText(); // throws, was forgotten outside the block above
|
|
206
|
+
interfaceDeclaration.getText(); // ok, hasn't been forgotten yet
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
moduleDeclaration.getText(); // ok, was marked to remember in one of the blocks
|
|
210
|
+
interfaceDeclaration.getText(); // throws, was forgotten
|
|
211
|
+
classDeclaration.getText(); // throws, was forgotten
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
##### Async
|
|
215
|
+
|
|
216
|
+
This method supports async and await:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
await project.forgetNodesCreatedInBlock(async remember => {
|
|
220
|
+
// do stuff
|
|
221
|
+
});
|
|
222
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Removing
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Removing
|
|
6
|
+
|
|
7
|
+
Given the source file for following code:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
enum MyEnum {
|
|
11
|
+
myMember,
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Removing can be done as follows:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const member = sourceFile.getEnum("MyEnum")!.getMember("myMember")!;
|
|
19
|
+
member.remove();
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
So the file above would now contain the following code:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
enum MyEnum {
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Support
|
|
30
|
+
|
|
31
|
+
Currently removing is implemented individually for each kind of node. In general this will work for many kind of nodes, including methods, properties, constructors, parmeters, statements, declarations. Nevertheless, if you find that `remove()` method is not implemented for a particular kind of Node, please open an issue on github.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Renaming
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Renaming
|
|
6
|
+
|
|
7
|
+
Given the source file for following code:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
enum MyEnum {
|
|
11
|
+
myMember,
|
|
12
|
+
}
|
|
13
|
+
const myVar = MyEnum.myMember;
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Renaming can be done as follows:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
const myEnum = sourceFile.getEnum("MyEnum")!;
|
|
20
|
+
myEnum.rename("NewEnum");
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Which will rename all usages of `MyEnum` to `NewEnum` across _all_ files.
|
|
24
|
+
|
|
25
|
+
So the file above would now contain the following code:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
enum NewEnum {
|
|
29
|
+
myMember,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const myVar = NewEnum.myMember;
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Renaming in comments and strings
|
|
36
|
+
|
|
37
|
+
Set the `renameInComments` and `renameInStrings` options to `true` (they are `false` by default):
|
|
38
|
+
|
|
39
|
+
```ts setup: let myEnum: EnumDeclaration;
|
|
40
|
+
myEnum.rename("SomeOtherName", {
|
|
41
|
+
renameInComments: true,
|
|
42
|
+
renameInStrings: true,
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Renaming with prefix and suffix text
|
|
47
|
+
|
|
48
|
+
**Note:** This feature is only supported when using TypeScript 3.4+
|
|
49
|
+
|
|
50
|
+
By default, renames will not change shorthand property assignments or add aliases to import & export specifiers.
|
|
51
|
+
|
|
52
|
+
For example, renaming the `a` variable declaration to `b`...
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const a = 5;
|
|
56
|
+
const x = { a };
|
|
57
|
+
|
|
58
|
+
export { a };
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
...will do the following:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const b = 5;
|
|
65
|
+
const x = { b };
|
|
66
|
+
|
|
67
|
+
export { b };
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This behaviour can be changed by enabling the `usePrefixAndSuffixText` setting, which will do the following:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const b = 5;
|
|
74
|
+
const x = { a: b };
|
|
75
|
+
|
|
76
|
+
export { b as a };
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This behaviour change can be specified when renaming:
|
|
80
|
+
|
|
81
|
+
```ts setup: let varA: VariableDeclaration;
|
|
82
|
+
varA.rename("SomeOtherName", {
|
|
83
|
+
usePrefixAndSuffixText: true,
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Or globally:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const project = new Project({
|
|
91
|
+
manipulationSettings: {
|
|
92
|
+
usePrefixAndSuffixTextForRename: true,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
// or
|
|
96
|
+
project.manipulationSettings.set({
|
|
97
|
+
usePrefixAndSuffixTextForRename: true,
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Renaming Files or Directories
|
|
102
|
+
|
|
103
|
+
See:
|
|
104
|
+
|
|
105
|
+
- [Moving Files](../details/source-files#move)
|
|
106
|
+
- [Moving Directories](../navigation/directories#moving)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Manipulation Settings
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Manipulation Settings
|
|
6
|
+
|
|
7
|
+
The manipulation settings can be set when creating the main `Project` object:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { IndentationText, NewLineKind, Project, QuoteKind } from "ts-morph";
|
|
11
|
+
|
|
12
|
+
const project = new Project({
|
|
13
|
+
// these are the defaults
|
|
14
|
+
manipulationSettings: {
|
|
15
|
+
// TwoSpaces, FourSpaces, EightSpaces, or Tab
|
|
16
|
+
indentationText: IndentationText.FourSpaces,
|
|
17
|
+
// LineFeed or CarriageReturnLineFeed
|
|
18
|
+
newLineKind: NewLineKind.LineFeed,
|
|
19
|
+
// Single or Double
|
|
20
|
+
quoteKind: QuoteKind.Double,
|
|
21
|
+
// Whether to change shorthand property assignments to property assignments
|
|
22
|
+
// and add aliases to import & export specifiers (see more information in
|
|
23
|
+
// the renaming section of the documentation).
|
|
24
|
+
usePrefixAndSuffixTextForRename: false,
|
|
25
|
+
// Whether to use trailing commas in multi-line scenarios where trailing
|
|
26
|
+
// commas would be used.
|
|
27
|
+
useTrailingCommas: false,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You can only provide a partial of these settings if you wish:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
const project = new Project({
|
|
36
|
+
manipulationSettings: { indentationText: IndentationText.TwoSpaces },
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Details
|
|
41
|
+
|
|
42
|
+
Get more details about the settings by looking at the `manipulationSettings` property on the main `Project` object:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
project.manipulationSettings.getIndentationText();
|
|
46
|
+
project.manipulationSettings.getNewLineKind();
|
|
47
|
+
project.manipulationSettings.getQuoteKind();
|
|
48
|
+
project.manipulationSettings.getUsePrefixAndSuffixTextForRename();
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Updating
|
|
52
|
+
|
|
53
|
+
You can update these settings later if you wish by using the `set` method:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
// set only one
|
|
57
|
+
project.manipulationSettings.set({ quoteKind: QuoteKind.Single });
|
|
58
|
+
|
|
59
|
+
// or multiple
|
|
60
|
+
project.manipulationSettings.set({
|
|
61
|
+
quoteKind: QuoteKind.Single,
|
|
62
|
+
indentationText: IndentationText.TwoSpaces,
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Formatting
|
|
67
|
+
|
|
68
|
+
There are some additional manipulation settings that are taken from the `ts.FormatCodeSettings`.
|
|
69
|
+
They will slowly be supported and added to the manipulation settings. For example:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
project.manipulationSettings.set({
|
|
73
|
+
// only one for now... will add more in the future
|
|
74
|
+
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: false, // default: true
|
|
75
|
+
});
|
|
76
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Structures
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Structures
|
|
6
|
+
|
|
7
|
+
Simplified AST representations called _structures_ can be retreived from and used to set many `Node` objects.
|
|
8
|
+
|
|
9
|
+
### Getting structure
|
|
10
|
+
|
|
11
|
+
To get the structure of a node, call `node.getStructure()`.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// example with a class declaration, but this also works on interfaces, enums, and many other nodes.
|
|
15
|
+
const classStructure = classDeclaration.getStructure(); // returns: ClassDeclarationStructure
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
In the example above, a class declaration like the following...
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
export class MyClass {
|
|
22
|
+
myProp = 5;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
...would return the following structure object similar to the following:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
{
|
|
30
|
+
isAbstract: false,
|
|
31
|
+
isExported: true,
|
|
32
|
+
name: "MyClass",
|
|
33
|
+
typeParameters: [],
|
|
34
|
+
constructors: [],
|
|
35
|
+
properties: [{
|
|
36
|
+
name: "myProp",
|
|
37
|
+
initializer: "5",
|
|
38
|
+
type: undefined,
|
|
39
|
+
isReadonly: false,
|
|
40
|
+
isStatic: false
|
|
41
|
+
}],
|
|
42
|
+
methods: []
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Setting with structure
|
|
47
|
+
|
|
48
|
+
It's also possible to set the structure of a node with an existing structure:
|
|
49
|
+
|
|
50
|
+
```ts setup: const classStructure = {};
|
|
51
|
+
classDeclaration.set(classStructure);
|
|
52
|
+
// sets the name
|
|
53
|
+
classDeclaration.set({ name: "NewName" });
|
|
54
|
+
// sets the properties
|
|
55
|
+
classDeclaration.set({ properties: [{ name: "newProperty" }] });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or you can use the `addX` or `insertX` methods with a structure:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
sourceFile.addClass({ name: "NewClass", ...classDeclaration.getStructure() });
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Traversing structures
|
|
65
|
+
|
|
66
|
+
#### `Structure` type guards
|
|
67
|
+
|
|
68
|
+
Similar to static methods found on `Node`, there is also a `Structure` export that you can use to check certain information about a structure.
|
|
69
|
+
|
|
70
|
+
For example:
|
|
71
|
+
|
|
72
|
+
```ts setup: const structure: Structures;
|
|
73
|
+
import { Structure } from "ts-morph";
|
|
74
|
+
|
|
75
|
+
// ...etc...
|
|
76
|
+
|
|
77
|
+
if (Structure.isExportable(structure))
|
|
78
|
+
structure.isExported = false;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### `forEachStructureChild`
|
|
82
|
+
|
|
83
|
+
Similar to the compiler API's `forEachChild`, there is a `forEachStructureChild` method in ts-morph for navigating over a structure's children.
|
|
84
|
+
|
|
85
|
+
For example:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { forEachStructureChild, SourceFileStructure, Structure } from "ts-morph";
|
|
89
|
+
|
|
90
|
+
const structure: SourceFileStructure = {
|
|
91
|
+
kind: StructureKind.SourceFile,
|
|
92
|
+
statements: [{
|
|
93
|
+
kind: StructureKind.Function,
|
|
94
|
+
name: "myFunction",
|
|
95
|
+
parameters: [{ name: "myParam" }],
|
|
96
|
+
}],
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
forEachStructureChild(structure, child => {
|
|
100
|
+
if (Structure.hasName(child))
|
|
101
|
+
console.log(child.name);
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Outputs: `"myFunction"`
|
|
106
|
+
|
|
107
|
+
##### Structures with no kind
|
|
108
|
+
|
|
109
|
+
Some structures have optional kinds. For example, in `parameters: [{ name: "myParam" }]` above, specifying `kind: StructureKind.Parameter` in the parameter would be unnecessarily repetitive. However, when using `forEachStructureChild`, you probably want to know the `kind` of the structure in order to do certain operations. For this reason, `forEachStructureChild` will automatically add the correct `kind` property to structures that don't have one.
|
|
110
|
+
|
|
111
|
+
##### Finding a child structure
|
|
112
|
+
|
|
113
|
+
Note that unlike ts-morph's `forEachChild`, this function acts like the `forEachChild` in the compiler API and will return any truthy value returned in the second argument's function:
|
|
114
|
+
|
|
115
|
+
```ts setup: const structure: SourceFileStructure;
|
|
116
|
+
const firstClassDecStructure = forEachStructureChild(structure, child => Structure.isClass(child) ? child : undefined);
|
|
117
|
+
```
|