@hanzogui/static 2.0.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.
Files changed (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/check-dep-versions.cjs +267 -0
  4. package/dist/checkDeps.cjs +200 -0
  5. package/dist/constants.cjs +49 -0
  6. package/dist/exports.cjs +44 -0
  7. package/dist/extractor/accessSafe.cjs +46 -0
  8. package/dist/extractor/babelParse.cjs +54 -0
  9. package/dist/extractor/buildClassName.cjs +62 -0
  10. package/dist/extractor/bundle.cjs +185 -0
  11. package/dist/extractor/bundleConfig.cjs +513 -0
  12. package/dist/extractor/concatClassName.cjs +80 -0
  13. package/dist/extractor/createEvaluator.cjs +75 -0
  14. package/dist/extractor/createExtractor.cjs +1150 -0
  15. package/dist/extractor/createLogger.cjs +45 -0
  16. package/dist/extractor/detectModuleFormat.cjs +49 -0
  17. package/dist/extractor/ensureImportingConcat.cjs +48 -0
  18. package/dist/extractor/errors.cjs +26 -0
  19. package/dist/extractor/esbuildAliasPlugin.cjs +44 -0
  20. package/dist/extractor/esbuildTsconfigPaths.cjs +86 -0
  21. package/dist/extractor/evaluateAstNode.cjs +83 -0
  22. package/dist/extractor/extractHelpers.cjs +119 -0
  23. package/dist/extractor/extractMediaStyle.cjs +128 -0
  24. package/dist/extractor/extractToClassNames.cjs +321 -0
  25. package/dist/extractor/extractToNative.cjs +266 -0
  26. package/dist/extractor/findTopmostFunction.cjs +34 -0
  27. package/dist/extractor/generatedUid.cjs +47 -0
  28. package/dist/extractor/getGuiConfigPathFromOptionsConfig.cjs +35 -0
  29. package/dist/extractor/getPrefixLogs.cjs +29 -0
  30. package/dist/extractor/getPropValueFromAttributes.cjs +67 -0
  31. package/dist/extractor/getSourceModule.cjs +64 -0
  32. package/dist/extractor/getStaticBindingsForScope.cjs +150 -0
  33. package/dist/extractor/hoistClassNames.cjs +62 -0
  34. package/dist/extractor/literalToAst.cjs +84 -0
  35. package/dist/extractor/loadFile.cjs +11 -0
  36. package/dist/extractor/loadGui.cjs +322 -0
  37. package/dist/extractor/logLines.cjs +35 -0
  38. package/dist/extractor/normalizeTernaries.cjs +73 -0
  39. package/dist/extractor/propsToFontFamilyCache.cjs +38 -0
  40. package/dist/extractor/regenerateConfig.cjs +150 -0
  41. package/dist/extractor/removeUnusedHooks.cjs +76 -0
  42. package/dist/extractor/timer.cjs +43 -0
  43. package/dist/extractor/validHTMLAttributes.cjs +77 -0
  44. package/dist/extractor/watchGuiConfig.cjs +58 -0
  45. package/dist/getPragmaOptions.cjs +58 -0
  46. package/dist/helpers/memoize.cjs +37 -0
  47. package/dist/helpers/requireGuiCore.cjs +33 -0
  48. package/dist/index.cjs +40 -0
  49. package/dist/registerRequire.cjs +115 -0
  50. package/dist/server.cjs +75 -0
  51. package/dist/setup.cjs +0 -0
  52. package/dist/types.cjs +16 -0
  53. package/dist/worker.cjs +89 -0
  54. package/package.json +101 -0
  55. package/src/check-dep-versions.ts +738 -0
  56. package/src/checkDeps.ts +371 -0
  57. package/src/constants.ts +14 -0
  58. package/src/exports.ts +15 -0
  59. package/src/extractor/accessSafe.ts +22 -0
  60. package/src/extractor/babelParse.ts +37 -0
  61. package/src/extractor/buildClassName.ts +76 -0
  62. package/src/extractor/bundle.ts +277 -0
  63. package/src/extractor/bundleConfig.ts +958 -0
  64. package/src/extractor/concatClassName.ts +105 -0
  65. package/src/extractor/createEvaluator.ts +82 -0
  66. package/src/extractor/createExtractor.ts +2665 -0
  67. package/src/extractor/createLogger.ts +41 -0
  68. package/src/extractor/detectModuleFormat.ts +42 -0
  69. package/src/extractor/ensureImportingConcat.ts +36 -0
  70. package/src/extractor/errors.ts +1 -0
  71. package/src/extractor/esbuildAliasPlugin.ts +40 -0
  72. package/src/extractor/esbuildTsconfigPaths.ts +103 -0
  73. package/src/extractor/evaluateAstNode.ts +136 -0
  74. package/src/extractor/extractHelpers.ts +211 -0
  75. package/src/extractor/extractMediaStyle.ts +194 -0
  76. package/src/extractor/extractToClassNames.ts +631 -0
  77. package/src/extractor/extractToNative.ts +463 -0
  78. package/src/extractor/findTopmostFunction.ts +24 -0
  79. package/src/extractor/generatedUid.ts +41 -0
  80. package/src/extractor/getGuiConfigPathFromOptionsConfig.ts +24 -0
  81. package/src/extractor/getPrefixLogs.ts +9 -0
  82. package/src/extractor/getPropValueFromAttributes.ts +95 -0
  83. package/src/extractor/getSourceModule.ts +96 -0
  84. package/src/extractor/getStaticBindingsForScope.ts +237 -0
  85. package/src/extractor/hoistClassNames.ts +52 -0
  86. package/src/extractor/literalToAst.ts +85 -0
  87. package/src/extractor/loadFile.ts +17 -0
  88. package/src/extractor/loadGui.ts +487 -0
  89. package/src/extractor/logLines.ts +16 -0
  90. package/src/extractor/normalizeTernaries.ts +75 -0
  91. package/src/extractor/propsToFontFamilyCache.ts +18 -0
  92. package/src/extractor/regenerateConfig.ts +186 -0
  93. package/src/extractor/removeUnusedHooks.ts +83 -0
  94. package/src/extractor/timer.ts +25 -0
  95. package/src/extractor/validHTMLAttributes.ts +52 -0
  96. package/src/extractor/watchGuiConfig.ts +57 -0
  97. package/src/getPragmaOptions.ts +57 -0
  98. package/src/helpers/memoize.ts +24 -0
  99. package/src/helpers/requireGuiCore.ts +28 -0
  100. package/src/index.ts +4 -0
  101. package/src/registerRequire.ts +236 -0
  102. package/src/server.ts +43 -0
  103. package/src/setup.ts +0 -0
  104. package/src/types.ts +109 -0
  105. package/src/worker.ts +142 -0
  106. package/types/check-dep-versions.d.ts +37 -0
  107. package/types/check-dep-versions.d.ts.map +1 -0
  108. package/types/checkDeps.d.ts +19 -0
  109. package/types/checkDeps.d.ts.map +1 -0
  110. package/types/constants.d.ts +6 -0
  111. package/types/constants.d.ts.map +1 -0
  112. package/types/exports.d.ts +16 -0
  113. package/types/exports.d.ts.map +1 -0
  114. package/types/extractor/accessSafe.d.ts +3 -0
  115. package/types/extractor/accessSafe.d.ts.map +1 -0
  116. package/types/extractor/babelParse.d.ts +5 -0
  117. package/types/extractor/babelParse.d.ts.map +1 -0
  118. package/types/extractor/buildClassName.d.ts +7 -0
  119. package/types/extractor/buildClassName.d.ts.map +1 -0
  120. package/types/extractor/bundle.d.ts +121 -0
  121. package/types/extractor/bundle.d.ts.map +1 -0
  122. package/types/extractor/bundleConfig.d.ts +49 -0
  123. package/types/extractor/bundleConfig.d.ts.map +1 -0
  124. package/types/extractor/concatClassName.d.ts +8 -0
  125. package/types/extractor/concatClassName.d.ts.map +1 -0
  126. package/types/extractor/createEvaluator.d.ts +12 -0
  127. package/types/extractor/createEvaluator.d.ts.map +1 -0
  128. package/types/extractor/createExtractor.d.ts +32 -0
  129. package/types/extractor/createExtractor.d.ts.map +1 -0
  130. package/types/extractor/createLogger.d.ts +3 -0
  131. package/types/extractor/createLogger.d.ts.map +1 -0
  132. package/types/extractor/detectModuleFormat.d.ts +5 -0
  133. package/types/extractor/detectModuleFormat.d.ts.map +1 -0
  134. package/types/extractor/ensureImportingConcat.d.ts +4 -0
  135. package/types/extractor/ensureImportingConcat.d.ts.map +1 -0
  136. package/types/extractor/errors.d.ts +3 -0
  137. package/types/extractor/errors.d.ts.map +1 -0
  138. package/types/extractor/esbuildAliasPlugin.d.ts +18 -0
  139. package/types/extractor/esbuildAliasPlugin.d.ts.map +1 -0
  140. package/types/extractor/esbuildTsconfigPaths.d.ts +11 -0
  141. package/types/extractor/esbuildTsconfigPaths.d.ts.map +1 -0
  142. package/types/extractor/evaluateAstNode.d.ts +3 -0
  143. package/types/extractor/evaluateAstNode.d.ts.map +1 -0
  144. package/types/extractor/extractHelpers.d.ts +28 -0
  145. package/types/extractor/extractHelpers.d.ts.map +1 -0
  146. package/types/extractor/extractMediaStyle.d.ts +11 -0
  147. package/types/extractor/extractMediaStyle.d.ts.map +1 -0
  148. package/types/extractor/extractToClassNames.d.ts +25 -0
  149. package/types/extractor/extractToClassNames.d.ts.map +1 -0
  150. package/types/extractor/extractToNative.d.ts +13 -0
  151. package/types/extractor/extractToNative.d.ts.map +1 -0
  152. package/types/extractor/findTopmostFunction.d.ts +4 -0
  153. package/types/extractor/findTopmostFunction.d.ts.map +1 -0
  154. package/types/extractor/generatedUid.d.ts +5 -0
  155. package/types/extractor/generatedUid.d.ts.map +1 -0
  156. package/types/extractor/getGuiConfigPathFromOptionsConfig.d.ts +3 -0
  157. package/types/extractor/getGuiConfigPathFromOptionsConfig.d.ts.map +1 -0
  158. package/types/extractor/getPrefixLogs.d.ts +3 -0
  159. package/types/extractor/getPrefixLogs.d.ts.map +1 -0
  160. package/types/extractor/getPropValueFromAttributes.d.ts +19 -0
  161. package/types/extractor/getPropValueFromAttributes.d.ts.map +1 -0
  162. package/types/extractor/getSourceModule.d.ts +16 -0
  163. package/types/extractor/getSourceModule.d.ts.map +1 -0
  164. package/types/extractor/getStaticBindingsForScope.d.ts +5 -0
  165. package/types/extractor/getStaticBindingsForScope.d.ts.map +1 -0
  166. package/types/extractor/hoistClassNames.d.ts +6 -0
  167. package/types/extractor/hoistClassNames.d.ts.map +1 -0
  168. package/types/extractor/literalToAst.d.ts +4 -0
  169. package/types/extractor/literalToAst.d.ts.map +1 -0
  170. package/types/extractor/loadFile.d.ts +1 -0
  171. package/types/extractor/loadFile.d.ts.map +1 -0
  172. package/types/extractor/loadGui.d.ts +22 -0
  173. package/types/extractor/loadGui.d.ts.map +1 -0
  174. package/types/extractor/logLines.d.ts +2 -0
  175. package/types/extractor/logLines.d.ts.map +1 -0
  176. package/types/extractor/normalizeTernaries.d.ts +3 -0
  177. package/types/extractor/normalizeTernaries.d.ts.map +1 -0
  178. package/types/extractor/propsToFontFamilyCache.d.ts +4 -0
  179. package/types/extractor/propsToFontFamilyCache.d.ts.map +1 -0
  180. package/types/extractor/regenerateConfig.d.ts +9 -0
  181. package/types/extractor/regenerateConfig.d.ts.map +1 -0
  182. package/types/extractor/removeUnusedHooks.d.ts +3 -0
  183. package/types/extractor/removeUnusedHooks.d.ts.map +1 -0
  184. package/types/extractor/timer.d.ts +5 -0
  185. package/types/extractor/timer.d.ts.map +1 -0
  186. package/types/extractor/validHTMLAttributes.d.ts +52 -0
  187. package/types/extractor/validHTMLAttributes.d.ts.map +1 -0
  188. package/types/extractor/watchGuiConfig.d.ts +5 -0
  189. package/types/extractor/watchGuiConfig.d.ts.map +1 -0
  190. package/types/getPragmaOptions.d.ts +8 -0
  191. package/types/getPragmaOptions.d.ts.map +1 -0
  192. package/types/helpers/memoize.d.ts +8 -0
  193. package/types/helpers/memoize.d.ts.map +1 -0
  194. package/types/helpers/requireGuiCore.d.ts +3 -0
  195. package/types/helpers/requireGuiCore.d.ts.map +1 -0
  196. package/types/index.d.ts +4 -0
  197. package/types/index.d.ts.map +1 -0
  198. package/types/registerRequire.d.ts +10 -0
  199. package/types/registerRequire.d.ts.map +1 -0
  200. package/types/server.d.ts +3 -0
  201. package/types/server.d.ts.map +1 -0
  202. package/types/setup.d.ts +1 -0
  203. package/types/setup.d.ts.map +1 -0
  204. package/types/types.d.ts +92 -0
  205. package/types/types.d.ts.map +1 -0
  206. package/types/worker.d.ts +46 -0
  207. package/types/worker.d.ts.map +1 -0
@@ -0,0 +1,738 @@
1
+ /**
2
+ * "license": "MIT",
3
+ "author": "Bryan Mishkin",
4
+ */
5
+
6
+ import { globSync } from 'fast-glob'
7
+ import { load } from 'js-yaml'
8
+ import { existsSync, readFileSync } from 'node:fs'
9
+ import { join, relative } from 'node:path'
10
+
11
+ type PackageJson = {
12
+ name?: string
13
+ version?: string
14
+ dependencies?: Record<string, string>
15
+ devDependencies?: Record<string, string>
16
+ peerDependencies?: Record<string, string>
17
+ optionalDependencies?: Record<string, string>
18
+ resolutions?: Record<string, string>
19
+ workspaces:
20
+ | string[]
21
+ | {
22
+ packages?: string
23
+ }
24
+ }
25
+
26
+ type DependenciesToVersionsSeen = Map<
27
+ string,
28
+ { package: Package; version: string; isLocalPackageVersion: boolean }[] // Array can't be readonly since we are adding to it.
29
+ >
30
+
31
+ /** A dependency, the versions present of it, and the packages each of those versions are seen in. */
32
+ type DependencyAndVersions = {
33
+ dependency: string
34
+ readonly versions: {
35
+ version: string
36
+ packages: readonly Package[]
37
+ }[]
38
+ }
39
+
40
+ /**
41
+ * Creates a map of each dependency in the workspace to an array of the packages it is used in.
42
+ *
43
+ * Example of such a map represented as an object:
44
+ *
45
+ * {
46
+ * 'ember-cli': [
47
+ * { package: Package...'@scope/package1', version: '~3.18.0' },
48
+ * { package: Package...'@scope/package2', version: '~3.18.0' }
49
+ * ]
50
+ * 'eslint': [
51
+ * { package: Package...'@scope/package1', version: '^7.0.0' },
52
+ * { package: Package...'@scope/package2', version: '^7.0.0' }
53
+ * ]
54
+ * }
55
+ */
56
+ function calculateVersionsForEachDependency(
57
+ packages: readonly Package[],
58
+ depType: readonly DEPENDENCY_TYPE[] = DEFAULT_DEP_TYPES
59
+ ): DependenciesToVersionsSeen {
60
+ const dependenciesToVersionsSeen: DependenciesToVersionsSeen = new Map<
61
+ string,
62
+ { package: Package; version: string; isLocalPackageVersion: boolean }[]
63
+ >()
64
+ for (const package_ of packages) {
65
+ recordDependencyVersionsForPackageJson(dependenciesToVersionsSeen, package_, depType)
66
+ }
67
+ return dependenciesToVersionsSeen
68
+ }
69
+
70
+ // eslint-disable-next-line complexity
71
+ function recordDependencyVersionsForPackageJson(
72
+ dependenciesToVersionsSeen: DependenciesToVersionsSeen,
73
+ package_: Package,
74
+ depType: readonly DEPENDENCY_TYPE[]
75
+ ) {
76
+ if (package_.packageJson.name && package_.packageJson.version) {
77
+ recordDependencyVersion(
78
+ dependenciesToVersionsSeen,
79
+ package_.packageJson.name,
80
+ package_.packageJson.version,
81
+ package_,
82
+ true
83
+ )
84
+ }
85
+
86
+ if (
87
+ depType.includes(DEPENDENCY_TYPE.dependencies) &&
88
+ package_.packageJson.dependencies
89
+ ) {
90
+ for (const [dependency, dependencyVersion] of Object.entries(
91
+ package_.packageJson.dependencies
92
+ )) {
93
+ if (dependencyVersion) {
94
+ recordDependencyVersion(
95
+ dependenciesToVersionsSeen,
96
+ dependency,
97
+ dependencyVersion,
98
+ package_
99
+ )
100
+ }
101
+ }
102
+ }
103
+
104
+ if (
105
+ depType.includes(DEPENDENCY_TYPE.devDependencies) &&
106
+ package_.packageJson.devDependencies
107
+ ) {
108
+ for (const [dependency, dependencyVersion] of Object.entries(
109
+ package_.packageJson.devDependencies
110
+ )) {
111
+ if (dependencyVersion) {
112
+ recordDependencyVersion(
113
+ dependenciesToVersionsSeen,
114
+ dependency,
115
+ dependencyVersion,
116
+ package_
117
+ )
118
+ }
119
+ }
120
+ }
121
+
122
+ if (
123
+ depType.includes(DEPENDENCY_TYPE.optionalDependencies) &&
124
+ package_.packageJson.optionalDependencies
125
+ ) {
126
+ for (const [dependency, dependencyVersion] of Object.entries(
127
+ package_.packageJson.optionalDependencies
128
+ )) {
129
+ if (dependencyVersion) {
130
+ recordDependencyVersion(
131
+ dependenciesToVersionsSeen,
132
+ dependency,
133
+ dependencyVersion,
134
+ package_
135
+ )
136
+ }
137
+ }
138
+ }
139
+
140
+ if (
141
+ depType.includes(DEPENDENCY_TYPE.peerDependencies) &&
142
+ package_.packageJson.peerDependencies
143
+ ) {
144
+ for (const [dependency, dependencyVersion] of Object.entries(
145
+ package_.packageJson.peerDependencies
146
+ )) {
147
+ if (dependencyVersion) {
148
+ recordDependencyVersion(
149
+ dependenciesToVersionsSeen,
150
+ dependency,
151
+ dependencyVersion,
152
+ package_
153
+ )
154
+ }
155
+ }
156
+ }
157
+
158
+ if (depType.includes(DEPENDENCY_TYPE.resolutions) && package_.packageJson.resolutions) {
159
+ for (const [dependency, dependencyVersion] of Object.entries(
160
+ package_.packageJson.resolutions
161
+ )) {
162
+ if (dependencyVersion) {
163
+ recordDependencyVersion(
164
+ dependenciesToVersionsSeen,
165
+ dependency,
166
+ dependencyVersion,
167
+ package_
168
+ )
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ function recordDependencyVersion(
175
+ dependenciesToVersionsSeen: DependenciesToVersionsSeen,
176
+ dependency: string,
177
+ version: string,
178
+ package_: Package,
179
+ isLocalPackageVersion = false
180
+ ) {
181
+ if (!dependenciesToVersionsSeen.has(dependency)) {
182
+ dependenciesToVersionsSeen.set(dependency, [])
183
+ }
184
+ const list = dependenciesToVersionsSeen.get(dependency)
185
+ /* istanbul ignore if */
186
+ if (list) {
187
+ // `list` should always exist at this point, this if statement is just to please TypeScript.
188
+ list.push({ package: package_, version, isLocalPackageVersion })
189
+ }
190
+ }
191
+
192
+ function calculateDependenciesAndVersions(
193
+ dependencyVersions: DependenciesToVersionsSeen
194
+ ): readonly DependencyAndVersions[] {
195
+ // Loop through all dependencies seen.
196
+ return [...dependencyVersions.entries()]
197
+ .sort((a, b) => a[0].localeCompare(b[0]))
198
+ .flatMap(([dependency, versionObjectsForDep]) => {
199
+ /* istanbul ignore if */
200
+ if (!versionObjectsForDep) {
201
+ // Should always exist at this point, this if statement is just to please TypeScript.
202
+ return []
203
+ }
204
+
205
+ // Check what versions we have seen for this dependency.
206
+ let versions = versionObjectsForDep
207
+ .filter((versionObject) => !versionObject.isLocalPackageVersion)
208
+ .map((versionObject) => versionObject.version)
209
+
210
+ // Check if this dependency is a local package.
211
+ const localPackageVersions = versionObjectsForDep
212
+ .filter((versionObject) => versionObject.isLocalPackageVersion)
213
+ .map((versionObject) => versionObject.version)
214
+ const allVersionsHaveWorkspacePrefix = versions.every((version) =>
215
+ version.startsWith('workspace:')
216
+ )
217
+ const hasIncompatibilityWithLocalPackageVersion = versions.some(
218
+ (version) => localPackageVersions[0] !== version
219
+ )
220
+ if (
221
+ localPackageVersions.length === 1 &&
222
+ !allVersionsHaveWorkspacePrefix &&
223
+ hasIncompatibilityWithLocalPackageVersion
224
+ ) {
225
+ // If we saw a version for this dependency that isn't compatible with its actual local package version, add the local package version to the list of versions seen.
226
+ // Note that using the `workspace:` prefix to refer to the local package version is allowed.
227
+ versions = [...versions, ...localPackageVersions]
228
+ }
229
+
230
+ // Calculate unique versions seen for this dependency.
231
+ const uniqueVersions = [...new Set(versions)]
232
+
233
+ const uniqueVersionsWithInfo = versionsObjectsWithSortedPackages(
234
+ uniqueVersions,
235
+ versionObjectsForDep
236
+ )
237
+ return {
238
+ dependency,
239
+ versions: uniqueVersionsWithInfo,
240
+ }
241
+ })
242
+ }
243
+
244
+ function versionsObjectsWithSortedPackages(
245
+ versions: readonly string[],
246
+ versionObjects: readonly {
247
+ package: Package
248
+ version: string
249
+ isLocalPackageVersion: boolean
250
+ }[]
251
+ ) {
252
+ return versions.map((version) => {
253
+ const matchingVersionObjects = versionObjects.filter(
254
+ (versionObject) => versionObject.version === version
255
+ )
256
+ return {
257
+ version,
258
+ packages: matchingVersionObjects
259
+ .map((object) => object.package)
260
+ .sort((a, b) => Package.comparator(a, b)),
261
+ }
262
+ })
263
+ }
264
+
265
+ const HARDCODED_IGNORED_DEPENDENCIES = new Set([
266
+ '//', // May be used to add comments to package.json files.
267
+ ])
268
+
269
+ function filterOutIgnoredDependencies(
270
+ mismatchingVersions: readonly DependencyAndVersions[],
271
+ ignoredDependencies: readonly string[],
272
+ includedDependencyPatterns: readonly RegExp[]
273
+ ): readonly DependencyAndVersions[] {
274
+ for (const ignoreDependency of ignoredDependencies) {
275
+ if (
276
+ !mismatchingVersions.some(
277
+ (mismatchingVersion) => mismatchingVersion.dependency === ignoreDependency
278
+ )
279
+ ) {
280
+ throw new Error(
281
+ `Specified option '--ignore-dep ${ignoreDependency}', but no version mismatches detected for this dependency.`
282
+ )
283
+ }
284
+ }
285
+
286
+ if (
287
+ ignoredDependencies.length > 0 ||
288
+ includedDependencyPatterns.length > 0 ||
289
+ mismatchingVersions.some((mismatchingVersion) =>
290
+ HARDCODED_IGNORED_DEPENDENCIES.has(mismatchingVersion.dependency)
291
+ )
292
+ ) {
293
+ return mismatchingVersions.filter(
294
+ (mismatchingVersion) =>
295
+ !ignoredDependencies.includes(mismatchingVersion.dependency) &&
296
+ includedDependencyPatterns.some((ignoreDependencyPattern) =>
297
+ mismatchingVersion.dependency.match(ignoreDependencyPattern)
298
+ ) &&
299
+ !HARDCODED_IGNORED_DEPENDENCIES.has(mismatchingVersion.dependency)
300
+ )
301
+ }
302
+
303
+ return mismatchingVersions
304
+ }
305
+
306
+ function getPackages(
307
+ root: string,
308
+ ignorePackages: readonly string[],
309
+ ignorePackagePatterns: readonly RegExp[],
310
+ ignorePaths: readonly string[],
311
+ ignorePathPatterns: readonly RegExp[]
312
+ ): readonly Package[] {
313
+ // Check for some error cases first.
314
+ if (!Package.exists(root)) {
315
+ throw new Error('No package.json found at provided path.')
316
+ }
317
+
318
+ const packages = accumulatePackages(root, ['.'])
319
+
320
+ for (const ignoredPackage of ignorePackages) {
321
+ if (
322
+ !Package.some(packages, (package_) => package_.name === ignoredPackage) // eslint-disable-line unicorn/no-array-method-this-argument,unicorn/no-array-callback-reference -- false positive
323
+ ) {
324
+ throw new Error(
325
+ `Specified option '--ignore-package ${ignoredPackage}', but no such package detected in workspace.`
326
+ )
327
+ }
328
+ }
329
+
330
+ for (const ignoredPackagePattern of ignorePackagePatterns) {
331
+ if (
332
+ // eslint-disable-next-line unicorn/no-array-method-this-argument,unicorn/no-array-callback-reference -- false positive
333
+ !Package.some(packages, (package_) => ignoredPackagePattern.test(package_.name))
334
+ ) {
335
+ throw new Error(
336
+ `Specified option '--ignore-package-pattern ${String(
337
+ ignoredPackagePattern
338
+ )}', but no matching packages detected in workspace.`
339
+ )
340
+ }
341
+ }
342
+
343
+ for (const ignoredPath of ignorePaths) {
344
+ if (
345
+ // eslint-disable-next-line unicorn/no-array-method-this-argument,unicorn/no-array-callback-reference -- false positive
346
+ !Package.some(packages, (package_) => package_.pathRelative.includes(ignoredPath))
347
+ ) {
348
+ throw new Error(
349
+ `Specified option '--ignore-path ${ignoredPath}', but no matching paths detected in workspace.`
350
+ )
351
+ }
352
+ }
353
+
354
+ for (const ignoredPathPattern of ignorePathPatterns) {
355
+ if (
356
+ // eslint-disable-next-line unicorn/no-array-method-this-argument,unicorn/no-array-callback-reference -- false positive
357
+ !Package.some(packages, (package_) =>
358
+ ignoredPathPattern.test(package_.pathRelative)
359
+ )
360
+ ) {
361
+ throw new Error(
362
+ `Specified option '--ignore-path-pattern ${String(
363
+ ignoredPathPattern
364
+ )}', but no matching paths detected in workspace.`
365
+ )
366
+ }
367
+ }
368
+
369
+ if (
370
+ ignorePackages.length > 0 ||
371
+ ignorePackagePatterns.length > 0 ||
372
+ ignorePaths.length > 0 ||
373
+ ignorePathPatterns.length > 0
374
+ ) {
375
+ return packages.filter(
376
+ (package_) =>
377
+ !ignorePackages.includes(package_.name) &&
378
+ !ignorePackagePatterns.some((ignorePackagePattern) =>
379
+ package_.name.match(ignorePackagePattern)
380
+ ) &&
381
+ !ignorePaths.some((ignorePath) => package_.pathRelative.includes(ignorePath)) &&
382
+ !ignorePathPatterns.some((ignorePathPattern) =>
383
+ package_.pathRelative.match(ignorePathPattern)
384
+ )
385
+ )
386
+ }
387
+
388
+ return packages
389
+ }
390
+
391
+ // Expand workspace globs into concrete paths.
392
+ function expandWorkspaces(
393
+ root: string,
394
+ workspacePatterns: readonly string[]
395
+ ): readonly string[] {
396
+ return workspacePatterns.flatMap((workspace) => {
397
+ if (!workspace.includes('*')) {
398
+ return [workspace]
399
+ }
400
+ // Use cwd instead of passing join()'d paths to globby for Windows support: https://github.com/micromatch/micromatch/blob/34f44b4f57eacbdbcc74f64252e0845cf44bbdbd/README.md?plain=1#L822
401
+ // Ignore any node_modules that may be present due to the use of nohoist.
402
+ return globSync(workspace, {
403
+ onlyDirectories: true,
404
+ cwd: root,
405
+ ignore: ['**/node_modules'],
406
+ })
407
+ })
408
+ }
409
+
410
+ // Recursively collect packages from a workspace.
411
+ function accumulatePackages(root: string, paths: readonly string[]): readonly Package[] {
412
+ const results: Package[] = []
413
+ for (const relativePath of paths) {
414
+ const path = join(root, relativePath)
415
+ if (Package.exists(path)) {
416
+ const package_ = new Package(path, root)
417
+ results.push(
418
+ // Add the current package.
419
+ package_,
420
+ // Recursively add any nested workspace packages that might exist here.
421
+ // This package is the new root.
422
+ ...accumulatePackages(path, expandWorkspaces(path, package_.workspacePatterns))
423
+ )
424
+ }
425
+ }
426
+ return results
427
+ }
428
+
429
+ /*
430
+ * Class to represent all of the information we need to know about a package in a workspace.
431
+ */
432
+ class Package {
433
+ /** Absolute path to package */
434
+ path: string
435
+ /** Absolute path to workspace.*/
436
+ pathWorkspace: string
437
+ /** Absolute path to package.json. */
438
+ pathPackageJson: string
439
+ packageJson: PackageJson
440
+ packageJsonEndsInNewline: boolean
441
+ pnpmWorkspacePackages?: readonly string[]
442
+
443
+ constructor(path: string, pathWorkspace: string) {
444
+ this.path = path
445
+ this.pathWorkspace = pathWorkspace
446
+
447
+ // package.json
448
+ this.pathPackageJson = join(path, 'package.json')
449
+ const packageJsonContents = readFileSync(this.pathPackageJson, 'utf8')
450
+ this.packageJsonEndsInNewline = packageJsonContents.endsWith('\n')
451
+ this.packageJson = JSON.parse(packageJsonContents) as PackageJson
452
+
453
+ // pnpm-workspace.yaml
454
+ const pnpmWorkspacePath = join(path, 'pnpm-workspace.yaml')
455
+ if (existsSync(pnpmWorkspacePath)) {
456
+ const pnpmWorkspaceContents = readFileSync(pnpmWorkspacePath, 'utf8')
457
+ const pnpmWorkspaceYaml = load(pnpmWorkspaceContents) as {
458
+ packages?: readonly string[]
459
+ }
460
+ this.pnpmWorkspacePackages = pnpmWorkspaceYaml.packages
461
+ }
462
+ }
463
+
464
+ get name(): string {
465
+ if (this.workspacePatterns.length > 0 && !this.packageJson.name) {
466
+ return '(Root)'
467
+ }
468
+ if (!this.packageJson.name) {
469
+ throw new Error(`${this.pathPackageJson} missing \`name\``)
470
+ }
471
+ return this.packageJson.name
472
+ }
473
+
474
+ /** Relative to workspace root. */
475
+ get pathRelative(): string {
476
+ return relative(this.pathWorkspace, this.path)
477
+ }
478
+
479
+ get workspacePatterns(): readonly string[] {
480
+ if (this.packageJson.workspaces) {
481
+ if (Array.isArray(this.packageJson.workspaces)) {
482
+ return this.packageJson.workspaces
483
+ } else if (this.packageJson.workspaces.packages) {
484
+ if (!Array.isArray(this.packageJson.workspaces.packages)) {
485
+ throw new TypeError('package.json `workspaces.packages` is not a string array.')
486
+ }
487
+ return this.packageJson.workspaces.packages
488
+ } else {
489
+ throw new TypeError('package.json `workspaces` is not a string array.')
490
+ }
491
+ }
492
+
493
+ if (this.pnpmWorkspacePackages) {
494
+ if (!Array.isArray(this.pnpmWorkspacePackages)) {
495
+ throw new TypeError('pnpm-workspace.yaml `packages` is not a string array.')
496
+ }
497
+ return this.pnpmWorkspacePackages
498
+ }
499
+
500
+ return []
501
+ }
502
+
503
+ static exists(path: string): boolean {
504
+ const packageJsonPath = join(path, 'package.json')
505
+ return existsSync(packageJsonPath)
506
+ }
507
+
508
+ static some(
509
+ packages: readonly Package[],
510
+ callback: (package_: Package) => boolean
511
+ ): boolean {
512
+ return packages.some((package_) => callback(package_))
513
+ }
514
+
515
+ static comparator(package1: Package, package2: Package) {
516
+ return package1.name.localeCompare(package2.name)
517
+ }
518
+ }
519
+
520
+ /** Map of dependency name to information about the dependency. */
521
+ type Dependencies = Record<
522
+ string,
523
+ {
524
+ isMismatching: boolean
525
+ versions: readonly {
526
+ version: string
527
+ packages: readonly Package[]
528
+ }[]
529
+ }
530
+ >
531
+
532
+ enum DEPENDENCY_TYPE {
533
+ dependencies = 'dependencies',
534
+ devDependencies = 'devDependencies',
535
+ optionalDependencies = 'optionalDependencies',
536
+ peerDependencies = 'peerDependencies',
537
+ resolutions = 'resolutions',
538
+ }
539
+
540
+ type Options = {
541
+ depType?: readonly `${DEPENDENCY_TYPE}`[] // Allow strings so the enum type doesn't always have to be used.
542
+ fix?: boolean
543
+ ignoreDep?: readonly string[]
544
+ includeDepPattern?: readonly string[]
545
+ ignorePackage?: readonly string[]
546
+ ignorePackagePattern?: readonly string[]
547
+ ignorePath?: readonly string[]
548
+ ignorePathPattern?: readonly string[]
549
+ }
550
+
551
+ const DEFAULT_DEP_TYPES = [
552
+ DEPENDENCY_TYPE.dependencies,
553
+ DEPENDENCY_TYPE.devDependencies,
554
+ DEPENDENCY_TYPE.optionalDependencies,
555
+ DEPENDENCY_TYPE.resolutions,
556
+ // peerDependencies is not included by default, see discussion in: https://github.com/bmish/check-dependency-version-consistency/issues/402
557
+ ]
558
+
559
+ /**
560
+ * Checks for inconsistencies across a workspace. Optionally fixes them.
561
+ * @param path - path to the workspace root
562
+ * @param options
563
+ * @param options.depType - Dependency type(s) to check
564
+ * @param options.fix - Whether to autofix inconsistencies (using latest version present)
565
+ * @param options.ignoreDep - Dependency(s) to ignore mismatches for
566
+ * @param options.includeDepPattern - RegExp(s) of dependency names to ignore mismatches for
567
+ * @param options.ignorePackage - Workspace package(s) to ignore mismatches for
568
+ * @param options.ignorePackagePattern - RegExp(s) of package names to ignore mismatches for
569
+ * @param options.ignorePath - Workspace-relative path(s) of packages to ignore mismatches for
570
+ * @param options.ignorePathPattern - RegExp(s) of workspace-relative path of packages to ignore mismatches for
571
+ * @returns an object with the following properties:
572
+ * - `dependencies`: An object mapping each dependency in the workspace to information about it including the versions found of it.
573
+ */
574
+ function check(path: string): {
575
+ dependencies: Dependencies
576
+ } {
577
+ const options: Options = {
578
+ includeDepPattern: ['@hanzo/gui', 'react-native-web-lite', 'react-native-web-internals'],
579
+ }
580
+
581
+ if (
582
+ options &&
583
+ options.depType &&
584
+ options.depType.some((dt) => !Object.keys(DEPENDENCY_TYPE).includes(dt))
585
+ ) {
586
+ throw new Error(
587
+ `Invalid depType provided. Choices are: ${Object.keys(DEPENDENCY_TYPE).join(', ')}.`
588
+ )
589
+ }
590
+
591
+ const optionsWithDefaults = {
592
+ fix: false,
593
+ ignoreDep: [],
594
+ includeDepPattern: [],
595
+ ignorePackage: [],
596
+ ignorePackagePattern: [],
597
+ ignorePath: [],
598
+ ignorePathPattern: [],
599
+ ...options,
600
+
601
+ // Fallback to default if no depType(s) provided.
602
+ depType:
603
+ options && options.depType && options.depType.length > 0
604
+ ? options.depType
605
+ : DEFAULT_DEP_TYPES,
606
+ }
607
+
608
+ // Calculate.
609
+ const packages = getPackages(
610
+ path,
611
+ optionsWithDefaults.ignorePackage,
612
+ optionsWithDefaults.ignorePackagePattern.map((s) => new RegExp(s)),
613
+ optionsWithDefaults.ignorePath,
614
+ optionsWithDefaults.ignorePathPattern.map((s) => new RegExp(s))
615
+ )
616
+
617
+ const dependencies = calculateVersionsForEachDependency(
618
+ packages,
619
+ optionsWithDefaults.depType.map((dt) => DEPENDENCY_TYPE[dt]) // Convert string to enum.
620
+ )
621
+ const dependenciesAndVersions = calculateDependenciesAndVersions(dependencies)
622
+ const dependenciesAndVersionsWithMismatches = dependenciesAndVersions.filter(
623
+ ({ versions }) => versions.length > 1
624
+ )
625
+
626
+ // Information about all dependencies.
627
+ const dependenciesAndVersionsWithoutIgnored = filterOutIgnoredDependencies(
628
+ dependenciesAndVersions,
629
+ optionsWithDefaults.ignoreDep,
630
+ optionsWithDefaults.includeDepPattern.map((s) => new RegExp(s))
631
+ )
632
+
633
+ // Information about mismatches.
634
+ const dependenciesAndVersionsMismatchesWithoutIgnored = filterOutIgnoredDependencies(
635
+ dependenciesAndVersionsWithMismatches,
636
+ optionsWithDefaults.ignoreDep,
637
+ optionsWithDefaults.includeDepPattern.map((s) => new RegExp(s))
638
+ )
639
+
640
+ return {
641
+ // Information about all dependencies.
642
+ dependencies: Object.fromEntries(
643
+ dependenciesAndVersionsWithoutIgnored.map(({ dependency, versions }) => {
644
+ return [
645
+ dependency,
646
+ {
647
+ isMismatching: dependenciesAndVersionsMismatchesWithoutIgnored.some(
648
+ (dep) => dep.dependency === dependency
649
+ ),
650
+ versions,
651
+ },
652
+ ]
653
+ })
654
+ ),
655
+ }
656
+ }
657
+
658
+ /** Relevant public data about a dependency. */
659
+ type Dependency = {
660
+ name: string
661
+ isMismatching: boolean
662
+ versions: readonly {
663
+ version: string
664
+ packages: readonly { pathRelative: string }[]
665
+ }[]
666
+ }
667
+
668
+ export class CDVC {
669
+ /** An object mapping each dependency in the workspace to information including the versions found of it. */
670
+ private readonly dependencies: Dependencies
671
+
672
+ /**
673
+ * @param path - path to the workspace root
674
+ * @param options
675
+ * @param options.fix - Whether to autofix inconsistencies (using latest version present)
676
+ * @param options.ignoreDep - Dependency(s) to ignore mismatches for
677
+ * @param options.includeDepPattern - RegExp(s) of dependency names to ignore mismatches for
678
+ * @param options.ignorePackage - Workspace package(s) to ignore mismatches for
679
+ * @param options.ignorePackagePattern - RegExp(s) of package names to ignore mismatches for
680
+ * @param options.ignorePath - Workspace-relative path(s) of packages to ignore mismatches for
681
+ * @param options.ignorePathPattern - RegExp(s) of workspace-relative path of packages to ignore mismatches for
682
+ */
683
+ constructor(path: string) {
684
+ const { dependencies } = check(path)
685
+ this.dependencies = dependencies
686
+ }
687
+
688
+ public toMismatchSummary(): string {
689
+ return dependenciesToMismatchSummary(this.dependencies)
690
+ }
691
+
692
+ public getDependencies(): readonly Dependency[] {
693
+ return Object.keys(this.dependencies).map((dependency) =>
694
+ this.getDependency(dependency)
695
+ )
696
+ }
697
+
698
+ public getDependency(name: string): Dependency {
699
+ // Convert underlying dependency data object with relevant public data.
700
+ return {
701
+ name,
702
+ isMismatching: this.dependencies[name].isMismatching,
703
+ versions: this.dependencies[name].versions.map((version) => ({
704
+ version: version.version,
705
+ packages: version.packages.map((package_) => ({
706
+ pathRelative: package_.pathRelative,
707
+ })),
708
+ })),
709
+ }
710
+ }
711
+
712
+ public get hasMismatchingDependencies(): boolean {
713
+ return Object.values(this.dependencies).some((dep) => dep.isMismatching)
714
+ }
715
+ }
716
+
717
+ function dependenciesToMismatchSummary(dependencies: Dependencies): string {
718
+ const mismatchingDependencyVersions = Object.entries(dependencies)
719
+ .filter(([, value]) => value.isMismatching)
720
+ .map(([dependency, value]) => ({ dependency, versions: value.versions }))
721
+
722
+ if (mismatchingDependencyVersions.length === 0) {
723
+ return ''
724
+ }
725
+
726
+ const tables = mismatchingDependencyVersions
727
+ .map((object) => {
728
+ return `${object.dependency} - ${object.versions.map((v) => `${v.version}`).join(', ')}`
729
+ })
730
+ .join('')
731
+
732
+ return [
733
+ `Found ${mismatchingDependencyVersions.length} ${
734
+ mismatchingDependencyVersions.length === 1 ? 'dependency' : 'dependencies'
735
+ } with mismatching versions across the workspace.`,
736
+ tables,
737
+ ].join('\n')
738
+ }