@haetae/javascript
@haetae/javascript
provides features for javascript ecosystem.
For instance, you can find out which module depends on which modules.
If your project do not use javascript-related languages, you don't need this package.
Ecosystem Supported
CJS (CommonJS), ESM (ES6 module), AMD, Typescript, JSX, TSX, Sass, Stylus,
Less, CSS (PostCSS), nodejs-only modules, browser-only modules are all supported.
peerDependencies
Note: This might not be exhaustive and lists only Haetae's packages.
Dependents
Installation
Are you developing a library(e.g. plugin) for Haetae?
It might be more suitable to specify @haetae/javascript
as peerDependencies
than dependencies
.
To automatically install @haetae/javascript
and its peerDependencies
You may want to install @haetae/javascript
and its peerDependencies
all at once.
install-peerdeps
(opens in a new tab) is a good tool for that.
# As dependencies
npx install-peerdeps @haetae/javascript
# As devDependencies
npx install-peerdeps --dev @haetae/javascript
To manually handle installation
You might want to manually deal with installation.
First, install @haetae/javascript
itself.
# As dependencies
npm install @haetae/javascript
# As devDependencies
npm install --save-dev @haetae/javascript
Then, check out peerDependencies
and manually handle them.
(e.g. Install them as dependencies
or set them as peerDependencies
)
# This does not install, but just show peerDependencies.
npm info @haetae/javascript peerDependencies
API
pkg
Refer to introduction#pkg.
VersionOptions
An argument interface for version
.
Type
interface VersionOptions {
rootDir?: string
}
version
A function to get version (not SemVer range, but the exact real version) of ny installed package.
Literally any package, like typescript
, jest
, react
, @changesets/cli
etc.
It supports npm, yarn classic, yarn berry and pnpm.
Not For Global Package
version
only works for local packages installed for your project, not globally installed packages on your system.
Type
(packageName: string, options?: VersionOptions) => Promise<string>
Arguments
packageName
: A package name to get the version of.options?
options.rootDir?
: A directory to start search. This should be your project root or its inner directory. (default:core.getConfigDirname()
)
Usage
You can get parsed object of any package's version by version
.
For example, let's assume eslint's version is 1.2.3-beta.4
.
import * as js from '@haetae/javascript'
const eslintVersion = await js.version('eslint')
eslintVersion.value // '1.2.3-beta.4'
eslintVersion.major // 1 // Integer
eslintVersion.minor // 2 // Integer
eslintVersion.patch // 3 // Integer
eslintVersion.prerelease // ['beta', 4] // 'beta' is string, 4 is integer
eslintVersion.untilMinor // '1.2'
eslintVersion.untilPatch // '1.2.3'
env
in the config file can be a good place to use version
.
import { core, js, utils } from 'haetae'
export default core.configure({
// Other options are ommitted for brevity.
commands: {
myLint: {
env: async () => ({
eslintrc: await utils.hash(['.eslintrc.js']),
eslint: (await js.version('eslint')).major,
}),
run: async () => { /* ... */ }
}
},
})
GraphOptions
An argument interface for graph
.
Type
interface GraphOptions {
entrypoint: string
tsConfig?: string
rootDir?: string
}
graph
A function to create a dependency graph.
it's not just for a specific language, but for any dependency graph.
Type
(options: GraphOptions) => utils.DepsGraph
Options?
entrypoint
: A starting point of a file to search the dependency graph.tsConfig?
: A path to Typescript config file. (e.g. tsconfig.json).rootDir?
: A directory to use whenentrypoint
ortsConfig
is given as relative paths. (default:core.getConfigDirname()
)
DependsOnOptions
An argument interface for dependsOn
Type
interface DependsOnOptions {
dependent: string
dependencies: readonly string[] | Set<string>
tsConfig?: string
rootDir?: string
additionalGraph?: utils.DepsGraph
}
dependsOn
A function to check if a module depends on one of the different modules, transitively or directly.
Multiple Formats Support
ES6(.js, .mjs), CJS(.js, .cjs), AMD, TypeScript(.ts, .mts, .cts), JSX(.jsx, .tsx), Webpack Loaders, CSS Preprocessors(Sass, Scss, Stylus, Less), PostCSS, RequireJS are all supported.
For node, Subpath Imports (opens in a new tab) and Subpath Exports (opens in a new tab) are also supported.
For TypeScript, Path Mapping (opens in a new tab) is also supported.
Type
(options: DependsOnOptions) => boolean
Options?
dependent
: A target to check if it is a dependent of at least one ofdependencies
, directly or transitively.dependencies
: Candidates that may be a dependency of dependent, directly or transitively.tsConfig?
: A path to typescript config file. (e.g. tsconfig.json).rootDir?
: A directory to executegit
. Whendependent
or an element ofdependencies
, ortsConfig
is given as a relative path,rootDir
is joined to transform it to an absolute path. (default:core.getConfigDirname()
)additionalGraph?
: A graph to manually specify explicit dependency relationships. This is purely additional, not an overrider or replacement of the original source code dependency graph. (default:)graph({ edges: [], rootDir })
Basic Usage
Let's say,
- a.ts depends on b.ts.
- c.ts depends on a.ts, which depends on b.ts
- e.ts does not (even transitively) depend on neither f.ts nor b.ts.
- f.ts does not (even transitively) depend on b.ts.
then the result would be like this.
const dependencies = ['f.ts', 'b.ts']
dependsOn({ dependent: 'a.ts', dependencies }) // true
dependsOn({ dependent: 'c.ts', dependencies }) // true -> transitively
dependsOn({ dependent: 'e.ts', dependencies }) // false
dependsOn({ dependent: 'f.ts', dependencies }) // true -> 'f.ts' depends on 'f.ts' itself.
Usage With git.changedFiles
It is a good practice to use with git.changedFiles
of @haetae/git
.
import { $, core, utils, git, js } from 'haetae'
export default core.configure({
// Other options are omitted for brevity
commands: {
myTest: {
env: { /* ... */ },
run: async () => {
const changedFiles = await git.changedFiles()
const testFiles = await utils.glob(['**/*.test.js'])
// An array of test files which (transitively) depend on changed files
const affectedTestFiles = testFiles.filter((testFile) =>
js.dependsOn({
dependent: testFile,
dependencies: changedFiles,
}),
)
if (affectedTestFiles.length > 0) {
// Equals to "pnpm jest /path/to/foo.test.ts /path/to/bar.test.ts ..."
// Change 'pnpm' and 'jest' to your package manager and test runner.
await $`pnpm jest ${affectedTestFiles.join(' ')}`
},
},
},
})
Usage With additionalGraph
Sometimes, automatic dependency resolution is not enough.
It only can find relationship between source code files, like .js, .jsx, .ts or .tsx.
You can specify additional dependency relationships manually.
Then dependsOn
would still automatically resolve the dependencies, but also check the given additionalGraph
.
import { utils, js } from 'haetae'
const additionalGraph = utils.graph({
edges: [
{
dependents: await utils.glob(['**/*.test.{ts,js}']),
dependencies:['.env.test', '.env.development'],
},
{
dependents: await utils.glob([
'tests/integration/**/*.test.ts',
'tests/e2e/**/*.test.tsx',
]),
dependencies: ['data-for-test.sql'],
},
],
})
// Other contexts are ommitted for brevity.
// Refer to the previous example snippet.
js.dependsOn({
dependent: file,
dependencies: changedFiles,
additionalGraph, // <= Added
})