cross-packer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +151 -0
- package/README.zh-CN.md +151 -0
- package/dist/archive/ar.d.ts +12 -0
- package/dist/archive/seven-za.d.ts +32 -0
- package/dist/archive/tar.d.ts +30 -0
- package/dist/archive/zip-reader.d.ts +17 -0
- package/dist/asar/dependency/collect.d.ts +2 -0
- package/dist/asar/dependency/detector.d.ts +8 -0
- package/dist/asar/dependency/hoister.d.ts +27 -0
- package/dist/asar/dependency/utils.d.ts +59 -0
- package/dist/asar/fileset/matcher.d.ts +12 -0
- package/dist/asar/fileset/platform-fileset.d.ts +36 -0
- package/dist/asar/fileset/transformer.d.ts +2 -0
- package/dist/asar/fileset/unpack-detector.d.ts +10 -0
- package/dist/asar/fileset/walker.d.ts +14 -0
- package/dist/asar/pack.d.ts +23 -0
- package/dist/asar/packer/app-collector.d.ts +2 -0
- package/dist/asar/packer/collector.d.ts +18 -0
- package/dist/asar/packer/concurrency.d.ts +1 -0
- package/dist/asar/packer/integrity.d.ts +8 -0
- package/dist/asar/packer/nm-collector.d.ts +7 -0
- package/dist/asar/packer/stream-builder.d.ts +18 -0
- package/dist/cli.d.ts +2 -0
- package/dist/config/index.d.ts +97 -0
- package/dist/electron/dist-zip.d.ts +18 -0
- package/dist/electron/download.d.ts +21 -0
- package/dist/index.d.ts +11 -0
- package/dist/packer/common/app-update-yml.d.ts +5 -0
- package/dist/packer/common/extra-resources.d.ts +39 -0
- package/dist/packer/common/staging.d.ts +3 -0
- package/dist/packer/common/template.d.ts +2 -0
- package/dist/packer/linux/linux.d.ts +2 -0
- package/dist/packer/mac/mac.d.ts +23 -0
- package/dist/packer/win/nsis.d.ts +24 -0
- package/dist/packer/win/resedit.d.ts +5 -0
- package/dist/packer/win/toolchain.d.ts +8 -0
- package/dist/packer/win/win.d.ts +12 -0
- package/dist/pipeline/pipeline.d.ts +41 -0
- package/dist/pipeline/targets.d.ts +28 -0
- package/dist/shared/hash.d.ts +2 -0
- package/dist/shared/logger.d.ts +39 -0
- package/dist/shared/platform.d.ts +26 -0
- package/dist/shared/types.d.ts +68 -0
- package/dist/update/blockmap.d.ts +13 -0
- package/dist/update/metadata.d.ts +20 -0
- package/dist/update/version.d.ts +7 -0
- package/package.json +71 -0
- package/src/archive/ar.ts +41 -0
- package/src/archive/seven-za.ts +160 -0
- package/src/archive/tar.ts +142 -0
- package/src/archive/zip-reader.ts +61 -0
- package/src/asar/dependency/collect.ts +437 -0
- package/src/asar/dependency/detector.ts +73 -0
- package/src/asar/dependency/hoister.ts +714 -0
- package/src/asar/dependency/utils.ts +225 -0
- package/src/asar/fileset/matcher.ts +101 -0
- package/src/asar/fileset/platform-fileset.ts +416 -0
- package/src/asar/fileset/transformer.ts +154 -0
- package/src/asar/fileset/unpack-detector.ts +38 -0
- package/src/asar/fileset/walker.ts +115 -0
- package/src/asar/pack.ts +186 -0
- package/src/asar/packer/app-collector.ts +74 -0
- package/src/asar/packer/collector.ts +134 -0
- package/src/asar/packer/concurrency.ts +24 -0
- package/src/asar/packer/integrity.ts +53 -0
- package/src/asar/packer/nm-collector.ts +194 -0
- package/src/asar/packer/stream-builder.ts +723 -0
- package/src/cli.ts +182 -0
- package/src/config/index.ts +365 -0
- package/src/electron/dist-zip.ts +65 -0
- package/src/electron/download.ts +121 -0
- package/src/index.ts +14 -0
- package/src/packer/common/app-update-yml.ts +21 -0
- package/src/packer/common/extra-resources.ts +83 -0
- package/src/packer/common/staging.ts +33 -0
- package/src/packer/common/template.ts +24 -0
- package/src/packer/linux/linux.ts +329 -0
- package/src/packer/mac/mac.ts +495 -0
- package/src/packer/win/nsis.ts +244 -0
- package/src/packer/win/resedit.ts +60 -0
- package/src/packer/win/toolchain.ts +63 -0
- package/src/packer/win/win.ts +421 -0
- package/src/pipeline/pipeline.ts +149 -0
- package/src/pipeline/targets.ts +67 -0
- package/src/shared/hash.ts +15 -0
- package/src/shared/logger.ts +91 -0
- package/src/shared/platform.ts +41 -0
- package/src/shared/types.ts +82 -0
- package/src/update/blockmap.ts +247 -0
- package/src/update/metadata.ts +97 -0
- package/src/update/version.ts +59 -0
- package/templates/linux/app.desktop +11 -0
- package/templates/linux/control +9 -0
- package/templates/linux/postinst +10 -0
- package/templates/linux/postrm +8 -0
- package/templates/linux/preinst +49 -0
- package/templates/linux/prerm +43 -0
- package/templates/mac/Info.plist +18 -0
- package/templates/mac/app-update.yml +4 -0
- package/templates/win/nsis/README.md +51 -0
- package/templates/win/nsis/THIRD-PARTY-NOTICES.md +20 -0
- package/templates/win/nsis/assistedInstaller.nsh +154 -0
- package/templates/win/nsis/assistedMessages.yml +368 -0
- package/templates/win/nsis/common.nsh +147 -0
- package/templates/win/nsis/empty-license.txt +1 -0
- package/templates/win/nsis/include/FileAssociation.nsh +123 -0
- package/templates/win/nsis/include/StdUtils.nsh +496 -0
- package/templates/win/nsis/include/StrContains.nsh +48 -0
- package/templates/win/nsis/include/UAC.nsh +299 -0
- package/templates/win/nsis/include/allowOnlyOneInstallerInstance.nsh +164 -0
- package/templates/win/nsis/include/extractAppPackage.nsh +138 -0
- package/templates/win/nsis/include/getProcessInfo.nsh +157 -0
- package/templates/win/nsis/include/installUtil.nsh +248 -0
- package/templates/win/nsis/include/installer.nsh +247 -0
- package/templates/win/nsis/include/nsProcess.nsh +28 -0
- package/templates/win/nsis/include/webPackage.nsh +64 -0
- package/templates/win/nsis/installSection.nsh +110 -0
- package/templates/win/nsis/installer.nsi +132 -0
- package/templates/win/nsis/messages.yml +240 -0
- package/templates/win/nsis/multiUser.nsh +134 -0
- package/templates/win/nsis/multiUserUi.nsh +230 -0
- package/templates/win/nsis/oneClick.nsh +19 -0
- package/templates/win/nsis/portable.nsi +91 -0
- package/templates/win/nsis/uninstaller.nsh +263 -0
- package/templates/win/nsis-header.nsh +57 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { readFile, realpath as realpathAsync } from 'node:fs/promises'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { hoist, type ShrunkNode, transformToHoisterTree } from './hoister.ts'
|
|
6
|
+
|
|
7
|
+
/** Raw dependency info extracted from a package manager's dependency graph. */
|
|
8
|
+
export interface RawDependencyInfo {
|
|
9
|
+
name: string
|
|
10
|
+
version: string
|
|
11
|
+
path?: string
|
|
12
|
+
_dependencies?: Record<string, string>
|
|
13
|
+
dependencies?: Record<string, RawDependencyInfo>
|
|
14
|
+
optionalDependencies?: Record<string, RawDependencyInfo>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Flattened dependency entry stored in allDependencies. */
|
|
18
|
+
export interface FlatDependency {
|
|
19
|
+
name: string
|
|
20
|
+
version: string
|
|
21
|
+
path: string
|
|
22
|
+
_dependencies?: Record<string, string>
|
|
23
|
+
dependencies?: Record<string, RawDependencyInfo>
|
|
24
|
+
optionalDependencies?: Record<string, RawDependencyInfo>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Node in the hoisted node_modules output tree. */
|
|
28
|
+
export interface HoistedNodeModule {
|
|
29
|
+
name: string
|
|
30
|
+
version: string
|
|
31
|
+
dir: string
|
|
32
|
+
dependencies?: HoistedNodeModule[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function execCommand(
|
|
36
|
+
command: string,
|
|
37
|
+
args: string[],
|
|
38
|
+
cwd?: string,
|
|
39
|
+
): Promise<{ stdout: string; stderr: string; error: Error | null }> {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
execFile(
|
|
42
|
+
command,
|
|
43
|
+
args,
|
|
44
|
+
{
|
|
45
|
+
cwd,
|
|
46
|
+
shell: true,
|
|
47
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
48
|
+
},
|
|
49
|
+
(error, stdout, stderr) => {
|
|
50
|
+
resolve({ stdout: stdout || '', stderr: stderr || '', error })
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Parse JSON from a command output, tolerating surrounding log noise. */
|
|
57
|
+
export function extractJsonFromOutput(output: string): unknown {
|
|
58
|
+
const trimmed = output.trim()
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(trimmed)
|
|
61
|
+
} catch {}
|
|
62
|
+
|
|
63
|
+
const bracketOpen = Math.max(trimmed.indexOf('{'), 0)
|
|
64
|
+
const bracketOpenSquare = Math.max(trimmed.indexOf('['), 0)
|
|
65
|
+
const start = Math.min(bracketOpen, bracketOpenSquare)
|
|
66
|
+
for (let i = start; i < trimmed.length; i++) {
|
|
67
|
+
const slice = trimmed.slice(start, i + 1)
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(slice)
|
|
70
|
+
} catch {}
|
|
71
|
+
}
|
|
72
|
+
throw new Error('No JSON content found in output')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function resolvePackageDir(nmDir: string, pkgName: string): string | null {
|
|
76
|
+
if (pkgName.startsWith('@')) {
|
|
77
|
+
const parts = pkgName.split('/')
|
|
78
|
+
if (parts.length < 2) return null
|
|
79
|
+
const dir = path.join(nmDir, parts[0], parts[1])
|
|
80
|
+
return existsSync(dir) ? dir : null
|
|
81
|
+
}
|
|
82
|
+
const dir = path.join(nmDir, pkgName)
|
|
83
|
+
return existsSync(dir) ? dir : null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function isProdDependency(
|
|
87
|
+
depName: string,
|
|
88
|
+
pkg: Pick<RawDependencyInfo, '_dependencies' | 'dependencies' | 'optionalDependencies'>,
|
|
89
|
+
): boolean {
|
|
90
|
+
const _deps = pkg._dependencies
|
|
91
|
+
if (_deps) return _deps[depName] != null
|
|
92
|
+
// Optional dependencies count as production deps when packing.
|
|
93
|
+
const prodDeps = { ...(pkg.dependencies || {}), ...(pkg.optionalDependencies || {}) }
|
|
94
|
+
return prodDeps[depName] != null
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Read the root package.json and derive its locator key. */
|
|
98
|
+
export async function readRootPkgJson(
|
|
99
|
+
projectDir: string,
|
|
100
|
+
): Promise<{ name: string; version: string; rootKey: string }> {
|
|
101
|
+
const pkgJson = JSON.parse(await readFile(path.join(projectDir, 'package.json'), 'utf8')) as {
|
|
102
|
+
name: string
|
|
103
|
+
version: string
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
name: pkgJson.name,
|
|
107
|
+
version: pkgJson.version,
|
|
108
|
+
rootKey: `${pkgJson.name}@${pkgJson.version}`,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function runHoistPipeline(
|
|
113
|
+
allDependencies: Map<string, FlatDependency>,
|
|
114
|
+
productionGraph: Record<string, { dependencies: string[] }>,
|
|
115
|
+
rootKey: string,
|
|
116
|
+
): Promise<{ nodeModules: HoistedNodeModule[] }> {
|
|
117
|
+
const hoisterTree = transformToHoisterTree(productionGraph, rootKey)
|
|
118
|
+
const hoistedResult = hoist(hoisterTree)
|
|
119
|
+
const nodeModules = await getNodeModulesFromHoisted(hoistedResult.dependencies, allDependencies)
|
|
120
|
+
return { nodeModules }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Detect npm's duplicated-dependency marker entries (no deps of their own). */
|
|
124
|
+
export function isDuplicatedNpmDependency(info: RawDependencyInfo | FlatDependency): boolean {
|
|
125
|
+
const _deps = info._dependencies || {}
|
|
126
|
+
const deps = info.dependencies || {}
|
|
127
|
+
return Object.keys(_deps).length > 0 && Object.keys(deps).length === 0
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function collectFromObjectTree(
|
|
131
|
+
deps: Record<string, RawDependencyInfo> | undefined,
|
|
132
|
+
allDependencies: Map<string, FlatDependency>,
|
|
133
|
+
): void {
|
|
134
|
+
if (!deps) return
|
|
135
|
+
for (const [name, info] of Object.entries(deps)) {
|
|
136
|
+
if (!info?.path) continue
|
|
137
|
+
const pkgDir = path.resolve(info.path)
|
|
138
|
+
const key = `${name}@${info.version}`
|
|
139
|
+
const entry: FlatDependency = {
|
|
140
|
+
name,
|
|
141
|
+
version: info.version,
|
|
142
|
+
path: pkgDir,
|
|
143
|
+
_dependencies: info._dependencies,
|
|
144
|
+
dependencies: info.dependencies,
|
|
145
|
+
optionalDependencies: info.optionalDependencies,
|
|
146
|
+
}
|
|
147
|
+
if (!isDuplicatedNpmDependency(info) || !allDependencies.has(key)) {
|
|
148
|
+
allDependencies.set(key, entry)
|
|
149
|
+
}
|
|
150
|
+
if (info.dependencies) {
|
|
151
|
+
collectFromObjectTree(info.dependencies, allDependencies)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function extractProdGraphFromObjectTree(
|
|
157
|
+
tree: RawDependencyInfo | undefined,
|
|
158
|
+
dependencyId: string,
|
|
159
|
+
productionGraph: Record<string, { dependencies: string[] }>,
|
|
160
|
+
allDependencies: Map<string, FlatDependency>,
|
|
161
|
+
): void {
|
|
162
|
+
if (productionGraph[dependencyId]) return
|
|
163
|
+
const isDuplicateDep = tree ? isDuplicatedNpmDependency(tree) : false
|
|
164
|
+
const targetTree = isDuplicateDep ? allDependencies.get(dependencyId) : tree
|
|
165
|
+
productionGraph[dependencyId] = { dependencies: [] }
|
|
166
|
+
const collectedDependencies: string[] = []
|
|
167
|
+
const deps = targetTree?.dependencies || {}
|
|
168
|
+
for (const name of Object.keys(deps)) {
|
|
169
|
+
const depInfo = deps[name]
|
|
170
|
+
if (!depInfo || Object.keys(depInfo).length === 0) continue
|
|
171
|
+
if (!targetTree || !isProdDependency(name, targetTree)) continue
|
|
172
|
+
const childDependencyId = `${name}@${depInfo.version}`
|
|
173
|
+
if (allDependencies.has(childDependencyId)) {
|
|
174
|
+
extractProdGraphFromObjectTree(depInfo, childDependencyId, productionGraph, allDependencies)
|
|
175
|
+
}
|
|
176
|
+
collectedDependencies.push(childDependencyId)
|
|
177
|
+
}
|
|
178
|
+
productionGraph[dependencyId] = { dependencies: collectedDependencies }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function buildProductionGraphFromFlat(
|
|
182
|
+
allDependencies: Map<string, FlatDependency>,
|
|
183
|
+
productionGraph: Record<string, { dependencies: string[] }>,
|
|
184
|
+
rootKey: string,
|
|
185
|
+
): void {
|
|
186
|
+
productionGraph[rootKey] = { dependencies: Array.from(allDependencies.keys()) }
|
|
187
|
+
for (const [key] of allDependencies) {
|
|
188
|
+
if (!productionGraph[key]) {
|
|
189
|
+
productionGraph[key] = { dependencies: [] }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Split a "name@version" identifier into its parts. */
|
|
195
|
+
export function parseNameVersion(identifier: string): { name: string; version: string } {
|
|
196
|
+
const lastAt = identifier.lastIndexOf('@')
|
|
197
|
+
if (lastAt <= 0) return { name: identifier, version: 'unknown' }
|
|
198
|
+
const name = identifier.slice(0, lastAt)
|
|
199
|
+
const version = identifier.slice(lastAt + 1)
|
|
200
|
+
return { name, version }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function getNodeModulesFromHoisted(
|
|
204
|
+
dependencies: Set<ShrunkNode>,
|
|
205
|
+
allDependencies: Map<string, FlatDependency>,
|
|
206
|
+
result: HoistedNodeModule[] = [],
|
|
207
|
+
): Promise<HoistedNodeModule[]> {
|
|
208
|
+
if (dependencies.size === 0) return result
|
|
209
|
+
for (const d of dependencies) {
|
|
210
|
+
const reference = [...d.references][0]
|
|
211
|
+
const key = `${d.name}@${reference}`
|
|
212
|
+
const depInfo = allDependencies.get(key)
|
|
213
|
+
if (depInfo === undefined || depInfo.path === undefined) continue
|
|
214
|
+
const resolvedPath = await realpathAsync(depInfo.path).catch(() => depInfo.path)
|
|
215
|
+
if (!existsSync(resolvedPath)) continue
|
|
216
|
+
const node: HoistedNodeModule = { name: d.name, version: reference, dir: resolvedPath }
|
|
217
|
+
result.push(node)
|
|
218
|
+
if (d.dependencies.size > 0) {
|
|
219
|
+
node.dependencies = []
|
|
220
|
+
await getNodeModulesFromHoisted(d.dependencies, allDependencies, node.dependencies)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
result.sort((a, b) => a.name.localeCompare(b.name))
|
|
224
|
+
return result
|
|
225
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import type { Minimatch } from 'minimatch'
|
|
3
|
+
import { EntryKind, type FileFilter, type FileStat } from '../../shared/types.ts'
|
|
4
|
+
|
|
5
|
+
export const excludedNames =
|
|
6
|
+
'.git,.hg,.svn,CVS,RCS,SCCS,' +
|
|
7
|
+
'__pycache__,.DS_Store,thumbs.db,.gitignore,.gitkeep,.gitattributes,.npmignore,' +
|
|
8
|
+
'.idea,.vs,.flowconfig,.jshintrc,.eslintrc,.circleci,' +
|
|
9
|
+
'.yarn-integrity,.yarn-metadata.json,yarn-error.log,yarn.lock,package-lock.json,npm-debug.log,pnpm-lock.yaml,bun.lock,bun.lockb,' +
|
|
10
|
+
'appveyor.yml,.travis.yml,circle.yml,.nyc_output,.husky,.github,electron-builder.env'
|
|
11
|
+
|
|
12
|
+
export const excludedExts =
|
|
13
|
+
'iml,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,suo,xproj,cc,d.ts,' + 'mk,a,o,obj,forge-meta'
|
|
14
|
+
|
|
15
|
+
export const excludedFiles = new Set(
|
|
16
|
+
[
|
|
17
|
+
'.DS_Store',
|
|
18
|
+
'node_modules',
|
|
19
|
+
'CHANGELOG.md',
|
|
20
|
+
'ChangeLog',
|
|
21
|
+
'changelog.md',
|
|
22
|
+
'Changelog.md',
|
|
23
|
+
'Changelog',
|
|
24
|
+
'binding.gyp',
|
|
25
|
+
'.npmignore',
|
|
26
|
+
'node_gyp_bins',
|
|
27
|
+
].concat(excludedNames.split(',')),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
export const topLevelExcludedFiles = new Set([
|
|
31
|
+
'karma.conf.js',
|
|
32
|
+
'.coveralls.yml',
|
|
33
|
+
'README.md',
|
|
34
|
+
'readme.markdown',
|
|
35
|
+
'README',
|
|
36
|
+
'readme.md',
|
|
37
|
+
'Readme.md',
|
|
38
|
+
'Readme',
|
|
39
|
+
'readme',
|
|
40
|
+
'test',
|
|
41
|
+
'tests',
|
|
42
|
+
'__tests__',
|
|
43
|
+
'powered-test',
|
|
44
|
+
'example',
|
|
45
|
+
'examples',
|
|
46
|
+
'.bin',
|
|
47
|
+
])
|
|
48
|
+
|
|
49
|
+
export function hasMagic(pattern: Minimatch): boolean {
|
|
50
|
+
const set = pattern.set
|
|
51
|
+
if (set.length > 1) return true
|
|
52
|
+
for (const i of set[0]) {
|
|
53
|
+
if (typeof i !== 'string') return true
|
|
54
|
+
}
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Ensure a path string ends with the platform separator. */
|
|
59
|
+
export function ensureEndSlash(s: string): string {
|
|
60
|
+
return s.length === 0 || s.endsWith(path.sep) ? s : s + path.sep
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function getRelativePath(file: string, srcWithEndSlash: string, stat: FileStat): string {
|
|
64
|
+
let relative = stat.moduleFullFilePath || file.substring(srcWithEndSlash.length)
|
|
65
|
+
if (path.sep === '\\') {
|
|
66
|
+
if (relative.startsWith('\\')) {
|
|
67
|
+
relative = relative.substring(1)
|
|
68
|
+
}
|
|
69
|
+
relative = relative.replace(/\\/g, '/')
|
|
70
|
+
}
|
|
71
|
+
return relative
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function minimatchAll(p: string, patterns: Minimatch[], stat: FileStat): boolean {
|
|
75
|
+
let match = false
|
|
76
|
+
for (const pattern of patterns) {
|
|
77
|
+
if (match !== pattern.negate) continue
|
|
78
|
+
match = pattern.match(p, stat.type === EntryKind.DIRECTORY && !pattern.negate)
|
|
79
|
+
}
|
|
80
|
+
return match
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function createFilter(
|
|
84
|
+
src: string,
|
|
85
|
+
patterns: Minimatch[],
|
|
86
|
+
excludePatterns?: Minimatch[] | null,
|
|
87
|
+
): FileFilter {
|
|
88
|
+
const srcWithEndSlash = ensureEndSlash(src)
|
|
89
|
+
return (file, stat) => {
|
|
90
|
+
if (src === file) return true
|
|
91
|
+
let relative = getRelativePath(file, srcWithEndSlash, stat)
|
|
92
|
+
if (relative === 'node_modules') return false
|
|
93
|
+
if (relative.endsWith('/node_modules')) relative += '/'
|
|
94
|
+
return (
|
|
95
|
+
minimatchAll(relative, patterns, stat) &&
|
|
96
|
+
(excludePatterns == null ||
|
|
97
|
+
stat.type === EntryKind.DIRECTORY ||
|
|
98
|
+
!minimatchAll(relative, excludePatterns, stat))
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
}
|