Skip to content

Commit

Permalink
feat(js): webpackConfig and skipNodeModules options
Browse files Browse the repository at this point in the history
`webpackConfig` and `skipNodeModules` options are added to functions related to a dependency graph.
Close #118
  • Loading branch information
jjangga0214 committed Jun 18, 2023
1 parent f4b02ec commit 230c51d
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/js-webpackConfig_skipNodeModules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@haetae/javascript': patch
---

`webpackConfig` and `skipNodeModules` options are added to functions related to a dependency graph.
38 changes: 33 additions & 5 deletions packages/docs/pages/apis/haetae-javascript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ eslintVersion.untilPatch // '1.2.3'
import { core, js, utils } from 'haetae'

export default core.configure({
// Other options are ommitted for brevity.
// Other options are omitted for brevity.
commands: {
myLint: {
env: async () => ({
Expand All @@ -187,6 +187,8 @@ An argument interface for [`graph`](#graph).
interface GraphOptions {
entrypoint: string
tsConfig?: string
webpackConfig?: string
skipNodeModules?: boolean
rootDir?: string
}
```
Expand All @@ -210,7 +212,12 @@ it's not just for a specific language, but for *any* dependency graph.
**Options?**

- `entrypoint{:ts}` : A starting point of a file to search the dependency graph.
- `tsConfig?{:ts}` : A path to Typescript config file. <small>(e.g. tsconfig.json)</small>.
- `tsConfig?{:ts}` : A path to Typescript config file.
<small>(default: *`tsconfig.json`* file by walking up parent directories recursively.)</small>.
- `webpackConfig?{:ts}` : A path to Webpack config file.
<small>(default: *`webpack.config.js`*, *`webpack.config.mjs`*, or *`webpack.config.cjs`* file
by walking up parent directories recursively.)</small>.
- `skipNodeModules?{:ts}` : Whether to exclude dependencies in *`node_modules`*. <small>(default: `true{:ts}`)</small>.
- `rootDir?{:ts}` : A directory to use when `entrypoint` or `tsConfig` is given as relative paths.
<small>(default: [`core.getConfigDirname(){:ts}`](./haetae-core#getconfigdirname))</small>

Expand All @@ -223,6 +230,8 @@ An argument interface for [`deps`](#deps).
interface DepsOptions {
entrypoint: string
tsConfig?: string
webpackConfig?: string
skipNodeModules?: boolean
rootDir?: string
additionalGraph?: utils.DepsGraph
}
Expand All @@ -243,7 +252,12 @@ The searched result keeps the order by breath-first approach, without duplicatio
**Options**

- `entrypoint{:ts}` : An entry point to get all of whose direct and transitive dependencies.
- `tsConfig?{:ts}` : A path to Typescript config file. <small>(e.g. tsconfig.json)</small>.
- `tsConfig?{:ts}` : A path to Typescript config file.
<small>(default: *`tsconfig.json`* file by walking up parent directories recursively.)</small>.
- `webpackConfig?{:ts}` : A path to Webpack config file.
<small>(default: *`webpack.config.js`*, *`webpack.config.mjs`*, or *`webpack.config.cjs`* file
by walking up parent directories recursively.)</small>.
- `skipNodeModules?{:ts}` : Whether to exclude dependencies in *`node_modules`*. <small>(default: `true{:ts}`)</small>.
- `rootDir?{:ts}` : A directory to join with when `entrypoint` is given as a relative path.
<small>(default: [`core.getConfigDirname(){:ts}`](./haetae-core#getconfigdirname))</small>
- `additionalGraph?{:ts}` : A graph to manually specify explicit dependency relationships.
Expand All @@ -268,6 +282,8 @@ interface DependsOnOptions {
dependent: string
dependencies: readonly string[]
tsConfig?: string
webpackConfig?: string
skipNodeModules?: boolean
rootDir?: string
additionalGraph?: utils.DepsGraph
glob?: boolean
Expand Down Expand Up @@ -303,7 +319,12 @@ There're [`dependOn`](#dependon) (plural) and [`dependsOn`](#dependson) (singula

- `dependent{:ts}` : A target to check if it is a dependent of at least one of `dependencies{:ts}`, directly or transitively.
- `dependencies{:ts}` : Candidates that may be a dependency of Dependents, directly or transitively.
- `tsConfig?{:ts}` : A path to typescript config file. <small>(e.g. **tsconfig.json**)</small>.
- `tsConfig?{:ts}` : A path to Typescript config file.
<small>(default: *`tsconfig.json`* file by walking up parent directories recursively.)</small>.
- `webpackConfig?{:ts}` : A path to Webpack config file.
<small>(default: *`webpack.config.js`*, *`webpack.config.mjs`*, or *`webpack.config.cjs`* file
by walking up parent directories recursively.)</small>.
- `skipNodeModules?{:ts}` : Whether to exclude dependencies in *`node_modules`*. <small>(default: `true{:ts}`)</small>.
- `rootDir?{:ts}` : A directory to join with when `dependent`, `dependencies`, or `tsConfig` is given as a relative path.
<small>(default: [`core.getConfigDirname(){:ts}`](./haetae-core#getconfigdirname))</small>
- `additionalGraph?{:ts}` : A graph to manually specify explicit dependency relationships.
Expand Down Expand Up @@ -350,6 +371,8 @@ interface DependOnOptions {
dependents: readonly string[]
dependencies: readonly string[]
tsConfig?: string
webpackConfig?: string
skipNodeModules?: boolean
rootDir?: string
additionalGraph?: utils.DepsGraph
glob?: boolean
Expand Down Expand Up @@ -387,7 +410,12 @@ There're [`dependOn`](#dependon) (plural) and [`dependsOn`](#dependson) (singula

- `dependents{:ts}` : Targets to filter by whether it's a dependent of at least one of `dependencies`, directly or transitively.
- `dependencies{:ts}` : Candidates that may be a dependency of dependent, directly or transitively.
- `tsConfig?{:ts}` : A path to typescript config file. <small>(e.g. **tsconfig.json**)</small>.
- `tsConfig?{:ts}` : A path to Typescript config file.
<small>(default: *`tsconfig.json`* file by walking up parent directories recursively.)</small>.
- `webpackConfig?{:ts}` : A path to Webpack config file.
<small>(default: *`webpack.config.js`*, *`webpack.config.mjs`*, or *`webpack.config.cjs`* file
by walking up parent directories recursively.)</small>.
- `skipNodeModules?{:ts}` : Whether to exclude dependencies in *`node_modules`*. <small>(default: `true{:ts}`)</small>.
- `rootDir?{:ts}` : A directory to join with when `dependents`, `dependencies`, or `tsConfig` is given as relative paths.
<small>(default: [`core.getConfigDirname(){:ts}`](./haetae-core#getconfigdirname))</small>
- `additionalGraph?{:ts}` : A graph to manually specify explicit dependency relationships.
Expand Down
95 changes: 73 additions & 22 deletions packages/js/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import fs from 'node:fs'
import fs from 'node:fs/promises'
import upath from 'upath'
import dependencyTree from 'dependency-tree'
import { dirname } from 'dirname-filename-esm'
import { parsePkg, toAbsolutePath } from '@haetae/common'
import filterAsync from 'node-filter-async'
import { findUp } from 'find-up'
import { parsePkg, toAbsolutePath } from '@haetae/common'
import * as core from '@haetae/core'
import * as utils from '@haetae/utils'

Expand All @@ -15,32 +16,76 @@ export const pkg = parsePkg({
rootDir: dirname(import.meta),
})

async function resolveEcosystemConfig(
file: string | undefined,
defaultFiles: string[],
rootDir: string,
): Promise<string | undefined> {
if (file) {
try {
await fs.access(file)
return file
} catch {
throw new Error(`file not found: ${file}`)
}
} else {
const founds = await Promise.all(
defaultFiles.map((defaultFile) =>
findUp(defaultFile, {
cwd: rootDir,
}),
),
)
for (const found of founds) {
if (found) {
return found
}
}
}
}

interface GraphOptions {
entrypoint: string
tsConfig?: string
webpackConfig?: string
skipNodeModules?: boolean
rootDir?: string
}

// Why async even though it doesn't use any async operation?
// That's to prevent breaking change from sync to async in the future.
export async function graph({
entrypoint,
rootDir = core.getConfigDirname(),
tsConfig,
webpackConfig,
skipNodeModules = true,
rootDir = core.getConfigDirname(),
}: GraphOptions): Promise<utils.DepsGraph> {
// eslint-disable-next-line no-param-reassign
/* eslint-disable no-param-reassign */
rootDir = toAbsolutePath({ path: rootDir, rootDir: core.getConfigDirname })
if (tsConfig) {
// eslint-disable-next-line no-param-reassign
tsConfig = upath.resolve(rootDir, tsConfig)
} else if (fs.existsSync(upath.resolve(rootDir, 'tsconfig.json'))) {
// eslint-disable-next-line no-param-reassign
tsConfig = upath.resolve(rootDir, 'tsconfig.json')
}
tsConfig = await resolveEcosystemConfig(tsConfig, ['tsconfig.json'], rootDir)
webpackConfig = await resolveEcosystemConfig(
webpackConfig,
[
'webpack.config.js',
'webpack.config.mjs',
'webpack.config.cjs',
// 'webpack.config.ts', TODO: support webpack.config.ts
// 'webpack.config.mts',
// 'webpack.config.cts',
],
rootDir,
)
/* eslint-enable no-param-reassign */

const baseTree = dependencyTree({
// All absolute paths by default
directory: rootDir,
filename: upath.resolve(rootDir, entrypoint),
tsConfig,
webpackConfig,
filter: (file) =>
skipNodeModules ? !file.includes('/node_modules/') : true,
})
const queue: dependencyTree.Tree[] = [baseTree]
const rawGraph: Record<string, string[]> = {}
Expand All @@ -62,14 +107,18 @@ export async function graph({

export interface DepsOptions {
entrypoint: string
rootDir?: string
tsConfig?: string
webpackConfig?: string
skipNodeModules?: boolean
rootDir?: string
additionalGraph?: utils.DepsGraph
}

export async function deps({
entrypoint,
tsConfig,
webpackConfig,
skipNodeModules,
rootDir = core.getConfigDirname(),
additionalGraph,
}: DepsOptions): Promise<string[]> {
Expand All @@ -82,6 +131,8 @@ export async function deps({
const jsGraph = await graph({
entrypoint,
tsConfig,
webpackConfig,
skipNodeModules,
rootDir,
})
const mergedGraph = utils.mergeGraphs([jsGraph, additionalGraph])
Expand All @@ -93,6 +144,8 @@ export interface DependsOnOptions {
dependent: string
dependencies: readonly string[]
tsConfig?: string
webpackConfig?: string
skipNodeModules?: boolean
rootDir?: string
additionalGraph?: utils.DepsGraph
glob?: boolean
Expand All @@ -102,6 +155,8 @@ export async function dependsOn({
dependent,
dependencies,
tsConfig, // TODO: automatic default tsconfig.json resolution by find-up
webpackConfig,
skipNodeModules,
rootDir = core.getConfigDirname(),
additionalGraph,
glob = true,
Expand All @@ -113,6 +168,8 @@ export async function dependsOn({
entrypoint: dependent,
rootDir,
tsConfig,
webpackConfig,
skipNodeModules,
})
const mergedGraph = utils.mergeGraphs([jsGraph, additionalGraph])

Expand All @@ -129,27 +186,21 @@ export interface DependOnOptions {
dependents: readonly string[]
dependencies: readonly string[]
tsConfig?: string
webpackConfig?: string
skipNodeModules?: boolean
rootDir?: string
additionalGraph?: utils.DepsGraph
glob?: boolean
}

export async function dependOn({
dependents,
dependencies,
tsConfig, // TODO: automatic default tsconfig.json resolution by find-up
rootDir,
additionalGraph,
glob,
...options
}: DependOnOptions): Promise<string[]> {
return filterAsync(dependents, (dependent) =>
dependsOn({
dependent,
dependencies,
tsConfig,
rootDir,
additionalGraph,
glob,
...options,
}),
)
}

1 comment on commit 230c51d

@vercel
Copy link

@vercel vercel bot commented on 230c51d Jun 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

haetae – ./

haetae-mu.vercel.app
haetae-git-main-jjangga0214.vercel.app
haetae-jjangga0214.vercel.app

Please sign in to comment.