Skip to content

Commit

Permalink
perf: Load SAPUI5 types only when needed (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
matz3 authored Mar 26, 2024
1 parent 57cf281 commit b7e9a2b
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 5 deletions.
37 changes: 35 additions & 2 deletions src/detectors/typeChecker/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,32 @@ async function collectTransitiveDependencies(pkgName: string, deps: Set<string>)
return deps;
}

async function collectSapui5TypesFiles() {
const typesDir = path.dirname(require.resolve("@sapui5/types/package.json"));
const allFiles = await fs.readdir(path.join(typesDir, "types"), {withFileTypes: true});
const typesFiles = [];
for (const entry of allFiles) {
if (entry.isFile() && entry.name.endsWith(".d.ts") && entry.name !== "index.d.ts") {
typesFiles.push(entry.name);
}
}
return typesFiles;
}

function addSapui5TypesMappingToCompilerOptions(sapui5TypesFiles: string[], options: ts.CompilerOptions) {
const paths = options.paths ?? (options.paths = {});
sapui5TypesFiles.forEach((fileName) => {
if (fileName === "sap.ui.core.d.ts") {
// No need to add a mapping for sap.ui.core, as it is loaded by default
return;
}
const libraryName = posixPath.basename(fileName, ".d.ts");
const namespace = libraryName.replace(/\./g, "/") + "/*";
const pathsEntry = paths[namespace] ?? (paths[namespace] = []);
pathsEntry.push(`/types/@sapui5/types/types/${fileName}`);
});
}

export async function createVirtualCompilerHost(
options: ts.CompilerOptions, files: Map<string, string>
): Promise<ts.CompilerHost> {
Expand All @@ -50,8 +76,15 @@ export async function createVirtualCompilerHost(
));

options.typeRoots = ["/types"];
// Request compiler to use all types we found in the dependencies of "@sapui5/types"
options.types = typePackageDirs;
options.types = [
// Request compiler to only use sap.ui.core types by default - other types will be loaded on demand
// (see addSapui5TypesMappingToCompilerOptions)
...typePackageDirs.filter((dir) => dir !== "/types/@sapui5/types/"),
"/types/@sapui5/types/types/sap.ui.core.d.ts",
];

// Adds mappings for all other sapui5 types, so that they are only loaded once a module is imported
addSapui5TypesMappingToCompilerOptions(await collectSapui5TypesFiles(), options);

// Create regex matching all path mapping keys
const pathMappingRegex = new RegExp(
Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/linter/projects/sap.f/src/sap/f/.library
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" ?>
<library xmlns="http://www.sap.com/sap.ui.library.xsd">
<name>sap.f</name>
<dependencies>
<dependency>
<libraryName>sap.ui.core</libraryName>
</dependency>
</dependencies>
</library>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// This project is used to test the linter with the namespace of an OpenUI5 project.
9 changes: 9 additions & 0 deletions test/fixtures/linter/projects/sap.f/test/sap/f/LinterTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This project is used to test the linter with the namespace of an OpenUI5 project.

sap.ui.require([
"sap/f/Avatar",
"sap/m/DateTimeInput"
], (Avatar, DateTimeInput) => {
new Avatar();
new DateTimeInput();
});
7 changes: 5 additions & 2 deletions test/fixtures/linter/rules/NoDeprecatedApi/NoDeprecatedApi.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
sap.ui.define([
"sap/m/Button", "sap/m/DateTimeInput", "sap/base/util/includes", "sap/ui/Device", "sap/ui/core/library",
"sap/m/Button", "sap/m/DateTimeInput", "sap/base/util/includes", "sap/ui/Device", "sap/ui/core/library", "sap/ui/generic/app/navigation/service/NavigationHandler",
"sap/ui/table/Table", "sap/ui/table/plugins/MultiSelectionPlugin", "sap/ui/core/Configuration", "sap/m/library"
], function(Button, DateTimeInput, includes, Device, coreLib, Table, MultiSelectionPlugin, Configuration, mobileLib) {
], function(Button, DateTimeInput, includes, Device, coreLib, NavigationHandler, Table, MultiSelectionPlugin, Configuration, mobileLib) {

var dateTimeInput = new DateTimeInput(); // TODO detect: Control is deprecated

Expand Down Expand Up @@ -34,4 +34,7 @@ sap.ui.define([
coreLib.MessageType; // Enum "MessageType" is deprecated

mobileLib.InputType.Date; // Enum value "InputType.Date" is deprecated

const navigationHandler = new NavigationHandler();
navigationHandler.storeInnerAppState({}); // Method "storeInnerAppState" is deprecated
});
18 changes: 18 additions & 0 deletions test/lib/linter/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,21 @@ test.serial("lint: All files of library.with.custom.paths", async (t) => {

t.snapshot(preprocessLintResultsForSnapshot(res));
});

test.serial("lint: All files of library with sap.f namespace", async (t) => {
const projectPath = path.join(fixturesProjectsPath, "sap.f");
const {lintProject} = t.context;

let res = await lintProject({
rootDir: projectPath,
filePaths: [],
reportCoverage: true,
messageDetails: true,
});

res = res.sort((a: {filePath: string}, b: {filePath: string}) => {
return a.filePath.localeCompare(b.filePath);
});

t.snapshot(preprocessLintResultsForSnapshot(res));
});
20 changes: 19 additions & 1 deletion test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Generated by [AVA](https://avajs.dev).
[
{
coverageInfo: [],
errorCount: 15,
errorCount: 17,
fatalErrorCount: 0,
filePath: 'NoDeprecatedApi.js',
messages: [
Expand All @@ -58,6 +58,15 @@ Generated by [AVA](https://avajs.dev).
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 107,
fatal: undefined,
line: 2,
message: 'Import of deprecated module \'sap/ui/generic/app/navigation/service/NavigationHandler\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 3,
fatal: undefined,
Expand Down Expand Up @@ -175,6 +184,15 @@ Generated by [AVA](https://avajs.dev).
ruleId: 'ui5-linter-no-deprecated-property',
severity: 2,
},
{
column: 2,
fatal: undefined,
line: 39,
message: 'Call to deprecated function \'storeInnerAppState\' of class \'NavigationHandler\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
],
warningCount: 0,
},
Expand Down
Binary file modified test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap
Binary file not shown.
42 changes: 42 additions & 0 deletions test/lib/linter/snapshots/linter.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -981,3 +981,45 @@ Generated by [AVA](https://avajs.dev).
warningCount: 0,
},
]

## lint: All files of library with sap.f namespace

> Snapshot 1
[
{
coverageInfo: [],
errorCount: 0,
fatalErrorCount: 0,
filePath: 'src/sap/f/LinterTest.js',
messages: [],
warningCount: 0,
},
{
coverageInfo: [],
errorCount: 2,
fatalErrorCount: 0,
filePath: 'test/sap/f/LinterTest.js',
messages: [
{
column: 2,
fatal: undefined,
line: 4,
message: 'Import of deprecated module \'sap/f/Avatar\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 2,
fatal: undefined,
line: 5,
message: 'Import of deprecated module \'sap/m/DateTimeInput\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
],
warningCount: 0,
},
]
Binary file modified test/lib/linter/snapshots/linter.ts.snap
Binary file not shown.

0 comments on commit b7e9a2b

Please sign in to comment.