diff --git a/.changeset/nasty-socks-flow.md b/.changeset/nasty-socks-flow.md new file mode 100644 index 0000000..57f245f --- /dev/null +++ b/.changeset/nasty-socks-flow.md @@ -0,0 +1,5 @@ +--- +'@callstack/react-native-legal-shared': minor +--- + +Feature: dependency scanning configuration for transitive & development dependencies diff --git a/README.md b/README.md index 4d9866f..f11e138 100644 --- a/README.md +++ b/README.md @@ -179,26 +179,7 @@ For a list of supported flags and the default values, run `npx license-kit --hel ### I want to customize the presentation of the licenses in my JS/TS project -You can use the `@callstack/react-native-legal-shared` package to access the core functionalities of the license management tool. Here's a basic example of how to use it: - -```typescript -import { - generateAboutLibrariesNPMOutput, - generateLicensePlistNPMOutput, - scanDependencies, -} from '@callstack/react-native-legal-shared'; - -// scan dependencies of a package -const licenses = scanDependencies(packageJsonPath); - -// generate AboutLibraries-compatible JSON metadata -const aboutLibrariesCompatibleReport = generateAboutLibrariesNPMOutput(licenses); - -// generate LicensePlist-compatible metadata -const licensePlistReport = generateLicensePlistNPMOutput(licenses); -``` - -For more advanced usage, read the [programmatic usage documentation](https://callstackincubator.github.io/react-native-legal/docs/programmatic-usage#usage). +You can use the `@callstack/react-native-legal-shared` package to access the core functionalities of the license management tool. To do so, please read the [programmatic usage documentation](https://callstackincubator.github.io/react-native-legal/docs/programmatic-usage#usage). ## Expo diff --git a/docs/docs/docs/programmatic-usage.mdx b/docs/docs/docs/programmatic-usage.mdx index 3d5a993..c0cf1f9 100644 --- a/docs/docs/docs/programmatic-usage.mdx +++ b/docs/docs/docs/programmatic-usage.mdx @@ -23,11 +23,19 @@ import { generateAboutLibrariesNPMOutput, generateLicensePlistNPMOutput, scanDependencies, + Types, } from '@callstack/react-native-legal-shared'; import * as md from 'ts-markdown-builder'; +// apart from dependencies, also include devDependencies, but only from the root package.json; +// also, include all transitive dependencies +const optionsFactory: Types.ScanPackageOptionsFactory = ({ isRoot }) => ({ + includeDevDependencies: isRoot, + includeTransitiveDependencies: true, +}); + // scan dependencies of a package -const licenses = scanDependencies(packageJsonPath); +const licenses = scanDependencies(packageJsonPath, optionsFactory); // generate AboutLibraries-compatible JSON metadata const aboutLibrariesCompatibleReport = generateAboutLibrariesNPMOutput(licenses); @@ -58,6 +66,14 @@ const markdownString = md .toString(); ``` +### Options + +As you can see in the example above, filtering for the packages to be included in the scan for dependencies is based on the passed in `ScanPackageOptionsFactory`. This factory would be invoked for every scanned `package.json` file, including the root and any considered dependencies and - given a `ScanPackageOptionsFactoryPackageInfo` object informing of the context of the package being scanned - should produce an accompanying configuration that would filter this package's dependencies. + +This approach gives a programmatic control at an arbitrary level of precision over filtering of dependencies to be included. + +As a reference, you can see how this is used in the `license-kit` CLI in [`createScanOptionsFactory` of `scanOptionsUtils.ts`](https://github.com/callstackincubator/react-native-legal/blob/main/packages/license-kit/src/scanOptionsUtils.ts). + ### API Documentation The API documentation is published under: https://callstackincubator.github.io/react-native-legal/api/. diff --git a/examples/bare-example/e2e/checkLicenses/android.yaml b/examples/bare-example/e2e/checkLicenses/android.yaml index 795fc89..c9fa8b4 100644 --- a/examples/bare-example/e2e/checkLicenses/android.yaml +++ b/examples/bare-example/e2e/checkLicenses/android.yaml @@ -1,5 +1,5 @@ appId: com.reactnativelegalbareexample -name: "[Android] Check React Native entry in OSS libraries list" +name: '[Android] Check React Native entry in OSS libraries list' tags: - pull-request - android @@ -10,12 +10,20 @@ tags: - startRecording: 'e2e_results/checkLicenses' - tapOn: 'Tap to see list of OSS libraries' - assertVisible: 'OSS Notice' +# workaround for long list issue taking ages to scroll to 'r*' packages (causing a timeout) +- repeat: + times: 7 + commands: + - swipe: + start: 50%, 90% + end: 50%, 0% + duration: 50 - scrollUntilVisible: element: containsChild: 'react-native' index: 0 direction: 'DOWN' - timeout: 120000 + timeout: 190000 centerElement: true speed: 70 - takeScreenshot: 'e2e_results/react-native_list_element' diff --git a/examples/bare-example/e2e/checkLicenses/ios.yaml b/examples/bare-example/e2e/checkLicenses/ios.yaml index a929714..77299c6 100644 --- a/examples/bare-example/e2e/checkLicenses/ios.yaml +++ b/examples/bare-example/e2e/checkLicenses/ios.yaml @@ -10,20 +10,27 @@ tags: - startRecording: 'e2e_results/checkLicenses' - tapOn: 'Tap to see list of OSS libraries' - assertVisible: 'OSS Notice' +# workaround for long list issue taking ages to scroll to 'r*' packages (causing a timeout) +- repeat: + times: 2 + commands: + - swipe: + start: 50%, 90% + end: 50%, 0% + duration: 50 - scrollUntilVisible: label: Scroll to React Native library - element: "react-native" + element: 'react-native' direction: 'DOWN' - timeout: 60000 + timeout: 100000 speed: 80 - takeScreenshot: 'e2e_results/react-native_list_element' -- tapOn: "react-native" +- tapOn: 'react-native' - takeScreenshot: 'e2e_results/react-native_entry' -- assertVisible: "react-native" -- assertVisible: "MIT License" -- assertVisible: "OSS Notice" -- tapOn: "OSS Notice" +- assertVisible: 'react-native' +- assertVisible: 'MIT License' +- assertVisible: 'OSS Notice' +- tapOn: 'OSS Notice' - takeScreenshot: 'e2e_results/react-native_back_to_list' - stopRecording - killApp - diff --git a/packages/license-kit/package.json b/packages/license-kit/package.json index 62048ea..497be20 100644 --- a/packages/license-kit/package.json +++ b/packages/license-kit/package.json @@ -28,7 +28,7 @@ "lint": "eslint \"**/*.{js,ts,tsx}\"", "clean": "rimraf build", "build-library": "tsc -p tsconfig.json", - "dev": "npx tsx src/index.ts" + "dev": "tsx src/index.ts" }, "keywords": [ "nodejs", @@ -55,6 +55,7 @@ "@types/jest": "^29.5.5", "jest": "^29.7.0", "rimraf": "^6.0.1", + "tsx": "^4.20.3", "typescript": "^5.8.3" }, "dependencies": { diff --git a/packages/shared/README.md b/packages/shared/README.md index 7346d3b..014b70e 100644 --- a/packages/shared/README.md +++ b/packages/shared/README.md @@ -21,11 +21,19 @@ import { generateAboutLibrariesNPMOutput, generateLicensePlistNPMOutput, scanDependencies, + Types, } from '@callstack/react-native-legal-shared'; import * as md from 'ts-markdown-builder'; +// apart from dependencies, also include devDependencies, but only from the root package.json; +// also, include all transitive dependencies +const optionsFactory: Types.ScanPackageOptionsFactory = ({ isRoot }) => ({ + includeDevDependencies: isRoot, + includeTransitiveDependencies: true, +}); + // scan dependencies of a package -const licenses = scanDependencies(packageJsonPath); +const licenses = scanDependencies(packageJsonPath, optionsFactory); // generate AboutLibraries-compatible JSON metadata const aboutLibrariesCompatibleReport = generateAboutLibrariesNPMOutput(licenses); diff --git a/packages/shared/src/common.ts b/packages/shared/src/common.ts index 8b99d08..2d199be 100644 --- a/packages/shared/src/common.ts +++ b/packages/shared/src/common.ts @@ -3,12 +3,13 @@ import path from 'path'; import glob from 'glob'; -import type { - AboutLibrariesLibraryJsonPayload, - AboutLibrariesLicenseJsonPayload, - AboutLibrariesLikePackageInfo, - AggregatedLicensesObj, - LicensePlistPayload, +import { + type AboutLibrariesLibraryJsonPayload, + type AboutLibrariesLicenseJsonPayload, + type AboutLibrariesLikePackageInfo, + type AggregatedLicensesObj, + type LicensePlistPayload, + type ScanPackageOptionsFactory, } from './types'; import { PackageUtils } from './utils'; @@ -20,6 +21,7 @@ function scanPackage( version: string, processedPackages: Set, result: AggregatedLicensesObj, + scanOptionsFactory: ScanPackageOptionsFactory = PackageUtils.legacyDefaultScanPackageOptionsFactory, ) { const packageKey = `${packageName}@${version}`; @@ -61,16 +63,27 @@ function scanPackage( } const dependencies = localPackageJson.dependencies; - + const devDependencies = localPackageJson.devDependencies; const isWorkspacePackage = version.startsWith('workspace:'); - if (!isWorkspacePackage) return; + const scanOptions = scanOptionsFactory({ + isRoot: false, + isWorkspacePackage, + }); - if (dependencies) { - Object.entries(dependencies).forEach(([depName, depVersion]) => { - scanPackage(depName, depVersion as string, processedPackages, result); - }); + // check if transitive dependencies should be scanned + if (!scanOptions.includeTransitiveDependencies) { + return; } + + [ + // transitive dependencies + ...(dependencies ? Object.entries(dependencies) : []), + // transitive devDependencies + ...(devDependencies && scanOptions.includeDevDependencies ? Object.entries(devDependencies) : []), + ].forEach(([depName, depVersion]) => { + scanPackage(depName, depVersion as string, processedPackages, result, scanOptionsFactory); + }); } catch (error) { console.warn(`[react-native-legal] could not process package.json for ${packageName}`); } @@ -79,17 +92,26 @@ function scanPackage( /** * Scans `package.json` and searches for all packages under `dependencies` field. Supports monorepo projects. */ -export function scanDependencies(appPackageJsonPath: string) { +export function scanDependencies( + appPackageJsonPath: string, + scanOptionsFactory: ScanPackageOptionsFactory = PackageUtils.legacyDefaultScanPackageOptionsFactory, +): AggregatedLicensesObj { const appPackageJson = require(path.resolve(appPackageJsonPath)); const dependencies: Record = appPackageJson.dependencies; + const devDependencies: Record = appPackageJson.devDependencies; const result: AggregatedLicensesObj = {}; const processedPackages = new Set(); - if (dependencies) { - Object.entries(dependencies).forEach(([packageName, version]) => { - scanPackage(packageName, version, processedPackages, result); - }); - } + const rootScanOptions = scanOptionsFactory({ isRoot: true, isWorkspacePackage: false }); + + [ + // dependencies + ...(dependencies ? Object.entries(dependencies) : []), + // devDependencies + ...(devDependencies && rootScanOptions.includeDevDependencies ? Object.entries(devDependencies) : []), + ].forEach(([packageName, version]) => { + scanPackage(packageName, version, processedPackages, result, scanOptionsFactory); + }); return result; } diff --git a/packages/shared/src/types/ScanPackageOptions.ts b/packages/shared/src/types/ScanPackageOptions.ts new file mode 100644 index 0000000..aa454ae --- /dev/null +++ b/packages/shared/src/types/ScanPackageOptions.ts @@ -0,0 +1,26 @@ +/** + * Scan options for controlling which dependencies of a package are scanned + */ +export type ScanPackageOptions = { + /** Whether transitive dependencies should be scanned */ + includeTransitiveDependencies: boolean; + + /** Whether to include devDependencies in the scan; include*Transitive* options apply */ + includeDevDependencies: boolean; +}; + +/** + * Information about a single package to be scanned + */ +export type ScanPackageOptionsFactoryPackageInfo = { + /** `true` if the analyzed package.json is the root of the scanned project */ + isRoot: boolean; + + /** `true` if the analyzed package.json is a dependency related to the project via a `workspace:...` dependency specifier */ + isWorkspacePackage: boolean; +}; + +/** + * Factory to create a filter for scan options for dependencies of a given package + */ +export type ScanPackageOptionsFactory = (packageInfo: ScanPackageOptionsFactoryPackageInfo) => ScanPackageOptions; diff --git a/packages/shared/src/types/index.ts b/packages/shared/src/types/index.ts index 1d768d7..5abd4bc 100644 --- a/packages/shared/src/types/index.ts +++ b/packages/shared/src/types/index.ts @@ -4,3 +4,4 @@ export * from './AboutLibrariesLibraryJsonPayload'; export * from './AboutLibrariesLicenseJsonPayload'; export * from './LicensePlistPayload'; export * from './AboutLibrariesLikePackageInfo'; +export * from './ScanPackageOptions'; diff --git a/packages/shared/src/utils/packageUtils.ts b/packages/shared/src/utils/packageUtils.ts index 077cd77..4f691d8 100644 --- a/packages/shared/src/utils/packageUtils.ts +++ b/packages/shared/src/utils/packageUtils.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import path from 'path'; -import type { LicenseObj } from '../types'; +import type { LicenseObj, ScanPackageOptionsFactory } from '../types'; import { sha512 } from './miscUtils'; import { normalizeRepositoryUrl } from './repositoryUtils'; @@ -80,3 +80,12 @@ export function parseRepositoryFieldToUrl(json: { repository: string | { url?: s return normalizeRepositoryUrl(json.repository); } } + +/** + * Default value consistent with legacy behaviour assumptions for the scan package options factory + * used so as not to introduce breaking API changes to the shared package + */ +export const legacyDefaultScanPackageOptionsFactory: ScanPackageOptionsFactory = () => ({ + includeTransitiveDependencies: true, + includeDevDependencies: false, +}); diff --git a/yarn.lock b/yarn.lock index 3f3356b..d987765 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4667,6 +4667,181 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/aix-ppc64@npm:0.25.5" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm64@npm:0.25.5" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-arm@npm:0.25.5" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/android-x64@npm:0.25.5" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-arm64@npm:0.25.5" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/darwin-x64@npm:0.25.5" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-arm64@npm:0.25.5" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/freebsd-x64@npm:0.25.5" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm64@npm:0.25.5" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-arm@npm:0.25.5" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ia32@npm:0.25.5" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-loong64@npm:0.25.5" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-mips64el@npm:0.25.5" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-ppc64@npm:0.25.5" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-riscv64@npm:0.25.5" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-s390x@npm:0.25.5" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/linux-x64@npm:0.25.5" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-arm64@npm:0.25.5" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/netbsd-x64@npm:0.25.5" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-arm64@npm:0.25.5" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/openbsd-x64@npm:0.25.5" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/sunos-x64@npm:0.25.5" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-arm64@npm:0.25.5" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-ia32@npm:0.25.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.25.5": + version: 0.25.5 + resolution: "@esbuild/win32-x64@npm:0.25.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" @@ -10821,6 +10996,92 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:~0.25.0": + version: 0.25.5 + resolution: "esbuild@npm:0.25.5" + dependencies: + "@esbuild/aix-ppc64": 0.25.5 + "@esbuild/android-arm": 0.25.5 + "@esbuild/android-arm64": 0.25.5 + "@esbuild/android-x64": 0.25.5 + "@esbuild/darwin-arm64": 0.25.5 + "@esbuild/darwin-x64": 0.25.5 + "@esbuild/freebsd-arm64": 0.25.5 + "@esbuild/freebsd-x64": 0.25.5 + "@esbuild/linux-arm": 0.25.5 + "@esbuild/linux-arm64": 0.25.5 + "@esbuild/linux-ia32": 0.25.5 + "@esbuild/linux-loong64": 0.25.5 + "@esbuild/linux-mips64el": 0.25.5 + "@esbuild/linux-ppc64": 0.25.5 + "@esbuild/linux-riscv64": 0.25.5 + "@esbuild/linux-s390x": 0.25.5 + "@esbuild/linux-x64": 0.25.5 + "@esbuild/netbsd-arm64": 0.25.5 + "@esbuild/netbsd-x64": 0.25.5 + "@esbuild/openbsd-arm64": 0.25.5 + "@esbuild/openbsd-x64": 0.25.5 + "@esbuild/sunos-x64": 0.25.5 + "@esbuild/win32-arm64": 0.25.5 + "@esbuild/win32-ia32": 0.25.5 + "@esbuild/win32-x64": 0.25.5 + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 2aa6f47c27a2f0fbf1e2eeed1df6c5449750ef598b9b49c95d8b654ec04423b70064de4f85a9e879c363402eb4f2fad59f37c996c329df1dc514b10f8ae76dd0 + languageName: node + linkType: hard + "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" @@ -12326,6 +12587,16 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: latest + checksum: 11e6ea6fea15e42461fc55b4b0e4a0a3c654faa567f1877dbd353f39156f69def97a69936d1746619d656c4b93de2238bf731f6085a03a50cabf287c9d024317 + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": version: 2.3.2 resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" @@ -12335,6 +12606,15 @@ __metadata: languageName: node linkType: hard +"fsevents@patch:fsevents@~2.3.3#~builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: latest + conditions: os=darwin + languageName: node + linkType: hard + "function-bind@npm:^1.1.1": version: 1.1.1 resolution: "function-bind@npm:1.1.1" @@ -12536,6 +12816,15 @@ __metadata: languageName: node linkType: hard +"get-tsconfig@npm:^4.7.5": + version: 4.10.1 + resolution: "get-tsconfig@npm:4.10.1" + dependencies: + resolve-pkg-maps: ^1.0.0 + checksum: 22925debda6bd0992171a44ee79a22c32642063ba79534372c4d744e0c9154abe2c031659da0fb86bc9e73fc56a3b76b053ea5d24ca3ac3da43d2e6f7d1c3c33 + languageName: node + linkType: hard + "getenv@npm:^1.0.0": version: 1.0.0 resolution: "getenv@npm:1.0.0" @@ -15398,6 +15687,7 @@ __metadata: jest: ^29.7.0 rimraf: ^6.0.1 ts-markdown-builder: ^0.4.1 + tsx: ^4.20.3 typescript: ^5.8.3 bin: license-kit: build/index.js @@ -19289,6 +19579,13 @@ __metadata: languageName: node linkType: hard +"resolve-pkg-maps@npm:^1.0.0": + version: 1.0.0 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 1012afc566b3fdb190a6309cc37ef3b2dcc35dff5fa6683a9d00cd25c3247edfbc4691b91078c97adc82a29b77a2660c30d791d65dab4fc78bfc473f60289977 + languageName: node + linkType: hard + "resolve-workspace-root@npm:^2.0.0": version: 2.0.0 resolution: "resolve-workspace-root@npm:2.0.0" @@ -21549,6 +21846,22 @@ __metadata: languageName: node linkType: hard +"tsx@npm:^4.20.3": + version: 4.20.3 + resolution: "tsx@npm:4.20.3" + dependencies: + esbuild: ~0.25.0 + fsevents: ~2.3.3 + get-tsconfig: ^4.7.5 + dependenciesMeta: + fsevents: + optional: true + bin: + tsx: dist/cli.mjs + checksum: 1d13d3168d9ea44b0d02a7df16cc39be8bf4c6c309768009f392ce54e8767402d1f2d13e8dd79d0d77ef4e8a61d96ea7bad12ab1d46f1a4dadf74c4b849d798e + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0"