Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions packages/dts-generator/src/generate-from-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,9 @@ export interface GenerateFromPathsConfig {
dependenciesDTSPathForCheck: string;

/**
* Comma-separated list of package names of the libraries on which the currently to-be-built types depends.
*
* This is meant for entire npm packages developed separately (often by others), not sibling libraries built in the same batch.
* E.g. when a custom UI5 control library is built by an application team, then it usually depends on the OpenUI5 types because
* those define the base classes like Control.
* Setting this has the effect that for the TS compilation check, the `types` field of the package.json file will be set to the
* respective package names and any other type packages are no longer considered.
*
* Only needed for the check.
* @deprecated Since 4.0.3. Declared @types/* dependencies are now auto-discovered
* from the nearest package.json. This option is still accepted for backward
* compatibility and merges additively with the discovered types.
*/
dependenciesTypePackagesForCheck?: string;

Expand Down
32 changes: 14 additions & 18 deletions packages/dts-generator/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ts from "typescript";
import { generateFromObjects, Directives } from "./generate-from-objects.js";
import { default as checkCompile } from "./checkCompile/check-compile.js";
import { writeFileSafe, loadJSON } from "./utils/file-utils.js";
import { discoverTypes } from "./utils/discover-types.js";

const loadedCache = new Map();

Expand Down Expand Up @@ -98,15 +99,9 @@ export type GenerateConfig = {
dependencyDTSFilesForCheck: string[];

/**
* Array of package names of the libraries on which the currently to-be-built types depends.
*
* This is meant for entire npm packages developed separately (often by others), not sibling libraries built in the same batch.
* E.g. when a custom UI5 control library is built by an application team, then it usually depends on the OpenUI5 types because
* those define the base classes like Control.
* Setting this has the effect that for the TS compilation check, the `types` field of the package.json file will be set to the
* respective package names and any other type packages are no longer considered.
*
* Only needed for the check.
* @deprecated Since 4.0.3. Declared @types/* dependencies are now auto-discovered
* from the nearest package.json. This option is still accepted for backward
* compatibility and merges additively with the discovered types.
*/
dependenciesTypePackagesForCheck?: string[];

Expand Down Expand Up @@ -170,23 +165,24 @@ export async function generate({
);

// set up the tsconfig for the test compile
const discovered = discoverTypes();
const tsOptions: ts.BuildOptions = {
noEmit: true,
noImplicitAny: true,
strict: true,
target: ts.ScriptTarget.ES2015,
module: ts.ModuleKind.ES2015,
module: ts.ModuleKind.ESNext,
moduleResolution: ts.ModuleResolutionKind.Bundler,
lib: ["lib.es2015.d.ts", "lib.dom.d.ts"],
...(discovered.typeRoots.length > 0 && {
typeRoots: discovered.typeRoots,
types: [
...discovered.types,
...(dependenciesTypePackagesForCheck || []),
],
}),
};

// if type dependencies are set, use them
if (
dependenciesTypePackagesForCheck &&
dependenciesTypePackagesForCheck.length > 0
) {
tsOptions.types = dependenciesTypePackagesForCheck;
}

const success = checkCompile({
mainFile: targetFile,
dependencyFiles: dependencyDTSFilesForCheck,
Expand Down
52 changes: 4 additions & 48 deletions packages/dts-generator/src/runCheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const log = getLogger("@ui5/dts-generator/runCheck");
import esMain from "es-main";

import * as path from "path";
import { promises as fsp, readdirSync, readFileSync } from "fs";
import { promises as fsp } from "fs";
const readdir = fsp.readdir;

import {
Expand All @@ -13,6 +13,7 @@ import {
ModuleKind,
ModuleResolutionKind,
} from "./index.js";
import { discoverTypes } from "./utils/discover-types.js";

async function findFiles(dir: string, extension: string) {
if (dir == null) {
Expand Down Expand Up @@ -48,52 +49,7 @@ async function main() {

const dtsFiles = await findFiles(dtsDir, "d.ts");

// TS6 no longer auto-includes @types packages; discover which ones are declared
// as dependencies and walk up from CWD to find where they're installed.
const declaredTypes = new Set<string>();
let dir = process.cwd();
while (true) {
try {
const pkg = JSON.parse(
readFileSync(path.join(dir, "package.json"), "utf8"),
);
for (const deps of [pkg.dependencies, pkg.devDependencies]) {
if (deps) {
for (const name of Object.keys(deps)) {
if (name.startsWith("@types/")) {
declaredTypes.add(name.slice("@types/".length));
}
}
}
}
break;
} catch {
// no package.json at this level
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}

const typeRoots: string[] = [];
const types = new Set<string>();
dir = process.cwd();
while (true) {
const candidate = path.join(dir, "node_modules", "@types");
try {
for (const entry of readdirSync(candidate, { withFileTypes: true })) {
if (entry.isDirectory() && declaredTypes.has(entry.name)) {
types.add(entry.name);
}
}
typeRoots.push(candidate);
} catch {
// doesn't exist at this level
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
const { typeRoots, types } = discoverTypes();

log.verbose(`Running a compile check for ${dtsFiles}`);
const success = checkCompile({
Expand All @@ -105,7 +61,7 @@ async function main() {
target: ScriptTarget.ES2015,
module: ModuleKind.ESNext,
moduleResolution: ModuleResolutionKind.Bundler,
...(typeRoots.length > 0 && { typeRoots, types: [...types] }),
...(typeRoots.length > 0 && { typeRoots, types }),
},
});

Expand Down
8 changes: 3 additions & 5 deletions packages/dts-generator/src/utils/arguments-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@ export const args = (() => {
});
parser.add_argument("--dependenciesTypePackagesForCheck", {
help:
"Comma-separated list of package names of the libraries on which the currently to-be-built types depends. This is meant for entire npm packages" +
" developed separately (often by others), not sibling libraries built in the same generation run. E.g. when a custom UI5 control library is built by an" +
" application team, then it usually depends on the OpenUI5 types because those define the base classes like Control. Setting this has the effect" +
" that for the TS compilation check, the `types` field of the package.json file will be set to the respective package names and any other type packages" +
" are no longer considered. Only needed for the check.",
"[DEPRECATED: @types packages are now auto-discovered from the nearest package.json] " +
"Comma-separated list of additional @types package names to include in the TS compilation check." +
" Typically no longer needed — declared @types/* dependencies are discovered automatically.",
});
parser.add_argument("--directivesPath", {
help: "Directory where the .dtsgenrc files for the libraries (current and dependencies) are located.",
Expand Down
51 changes: 51 additions & 0 deletions packages/dts-generator/src/utils/discover-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as path from "path";
import { readdirSync, readFileSync } from "fs";

export function discoverTypes(): { typeRoots: string[]; types: string[] } {
const declaredTypes = new Set<string>();
let dir = process.cwd();
while (true) {
try {
const pkg = JSON.parse(
readFileSync(path.join(dir, "package.json"), "utf8"),
);
for (const deps of [pkg.dependencies, pkg.devDependencies]) {
if (deps) {
for (const name of Object.keys(deps)) {
if (name.startsWith("@types/")) {
declaredTypes.add(name.slice("@types/".length));
}
}
}
}
break;
} catch {
// no package.json at this level
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}

const typeRoots: string[] = [];
const types = new Set<string>();
dir = process.cwd();
while (true) {
const candidate = path.join(dir, "node_modules", "@types");
try {
for (const entry of readdirSync(candidate, { withFileTypes: true })) {
if (entry.isDirectory() && declaredTypes.has(entry.name)) {
types.add(entry.name);
}
}
typeRoots.push(candidate);
} catch {
// doesn't exist at this level
}
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}

return { typeRoots, types: [...types] };
}
Loading