typesync 0.13.3 → 0.13.5-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 (57) hide show
  1. package/README.md +23 -25
  2. package/bin/typesync +2 -2
  3. package/{lib → dist}/cli-util.d.ts +17 -17
  4. package/{lib → dist}/cli.d.ts +2 -2
  5. package/dist/cli.js +297 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config-service.d.ts +11 -0
  8. package/dist/globber.d.ts +15 -0
  9. package/dist/index.d.ts +4 -0
  10. package/dist/index.js +3 -0
  11. package/dist/package-json-file-service.d.ts +15 -0
  12. package/dist/package-source.d.ts +25 -0
  13. package/dist/type-syncer-C_rkDNfx.js +320 -0
  14. package/dist/type-syncer-C_rkDNfx.js.map +1 -0
  15. package/dist/type-syncer.d.ts +13 -0
  16. package/dist/types.d.ts +103 -0
  17. package/dist/util.d.ts +53 -0
  18. package/dist/versioning.d.ts +14 -0
  19. package/dist/workspace-resolver.d.ts +75 -0
  20. package/package.json +33 -53
  21. package/lib/cli-util.js +0 -74
  22. package/lib/cli-util.js.map +0 -1
  23. package/lib/cli.js +0 -145
  24. package/lib/cli.js.map +0 -1
  25. package/lib/config-service.d.ts +0 -11
  26. package/lib/config-service.js +0 -61
  27. package/lib/config-service.js.map +0 -1
  28. package/lib/fs-utils.js +0 -28
  29. package/lib/fs-utils.js.map +0 -1
  30. package/lib/globber.d.ts +0 -15
  31. package/lib/globber.js +0 -43
  32. package/lib/globber.js.map +0 -1
  33. package/lib/index.d.ts +0 -4
  34. package/lib/index.js +0 -21
  35. package/lib/index.js.map +0 -1
  36. package/lib/package-json-file-service.d.ts +0 -15
  37. package/lib/package-json-file-service.js +0 -48
  38. package/lib/package-json-file-service.js.map +0 -1
  39. package/lib/package-source.d.ts +0 -25
  40. package/lib/package-source.js +0 -49
  41. package/lib/package-source.js.map +0 -1
  42. package/lib/type-syncer.d.ts +0 -13
  43. package/lib/type-syncer.js +0 -237
  44. package/lib/type-syncer.js.map +0 -1
  45. package/lib/types.d.ts +0 -103
  46. package/lib/types.js +0 -14
  47. package/lib/types.js.map +0 -1
  48. package/lib/util.d.ts +0 -53
  49. package/lib/util.js +0 -142
  50. package/lib/util.js.map +0 -1
  51. package/lib/versioning.d.ts +0 -14
  52. package/lib/versioning.js +0 -48
  53. package/lib/versioning.js.map +0 -1
  54. package/lib/workspace-resolver.d.ts +0 -79
  55. package/lib/workspace-resolver.js +0 -70
  56. package/lib/workspace-resolver.js.map +0 -1
  57. /package/{lib → dist}/fs-utils.d.ts +0 -0
@@ -0,0 +1,320 @@
1
+ import * as path$1 from "node:path";
2
+ import * as path from "node:path";
3
+ import { cosmiconfig } from "cosmiconfig";
4
+ import fetch from "npm-registry-fetch";
5
+ import { compare, parse } from "semver";
6
+
7
+ //#region src/types.ts
8
+ let IDependencySection = function(IDependencySection$1) {
9
+ IDependencySection$1["dev"] = "dev";
10
+ IDependencySection$1["deps"] = "deps";
11
+ IDependencySection$1["optional"] = "optional";
12
+ IDependencySection$1["peer"] = "peer";
13
+ return IDependencySection$1;
14
+ }({});
15
+
16
+ //#endregion
17
+ //#region src/util.ts
18
+ function uniq(source) {
19
+ return [...new Set(source)];
20
+ }
21
+ function shrinkObject(source) {
22
+ const object = {};
23
+ for (const key in source) if (source[key] !== undefined) object[key] = source[key];
24
+ return object;
25
+ }
26
+ function mergeObjects(source) {
27
+ return source.reduce((accum, next) => ({
28
+ ...accum,
29
+ ...next
30
+ }), {});
31
+ }
32
+ function typed(name) {
33
+ if (/^@.*?\//i.test(name)) {
34
+ const splat = name.split("/");
35
+ return `@types/${splat[0].slice(1)}__${splat[1]}`;
36
+ }
37
+ return `@types/${name}`;
38
+ }
39
+ function orderObject(source, comparer) {
40
+ const keys = Object.keys(source).sort(comparer);
41
+ const result = {};
42
+ for (const key of keys) result[key] = source[key];
43
+ return result;
44
+ }
45
+ function memoizeAsync(fn) {
46
+ const cache = new Map();
47
+ async function run(...args) {
48
+ try {
49
+ return await fn(...args);
50
+ } catch (err) {
51
+ cache.delete(args[0]);
52
+ throw err;
53
+ }
54
+ }
55
+ return async function(...args) {
56
+ const key = args[0];
57
+ if (cache.has(key)) return cache.get(key);
58
+ const p = run(...args);
59
+ cache.set(key, p);
60
+ return p;
61
+ };
62
+ }
63
+ function ensureWorkspacesArray(data) {
64
+ if (!data) return [];
65
+ if (!Array.isArray(data)) return ensureWorkspacesArray(data.packages);
66
+ if (!data.every((s) => typeof s === "string")) return [];
67
+ return data;
68
+ }
69
+
70
+ //#endregion
71
+ //#region src/config-service.ts
72
+ const explorer = cosmiconfig("typesync");
73
+ function createConfigService() {
74
+ return { readConfig: async (filePath, flags) => {
75
+ const fileConfig = await explorer.search(path$1.dirname(filePath)).then((result) => result?.config ?? {});
76
+ const cliConfig = readCliConfig(flags);
77
+ return {
78
+ ...shrinkObject(fileConfig),
79
+ ...shrinkObject(cliConfig)
80
+ };
81
+ } };
82
+ }
83
+ function readCliConfig(flags) {
84
+ const readValues = (key, validator) => {
85
+ const values = flags[key];
86
+ return typeof values === "string" ? values.split(",").filter((value) => validator ? validator(value) : true) : undefined;
87
+ };
88
+ return {
89
+ ignoreDeps: readValues("ignoredeps", isIgnoreDepConfigValue),
90
+ ignorePackages: readValues("ignorepackages"),
91
+ ignoreProjects: readValues("ignoreprojects")
92
+ };
93
+ }
94
+ function isIgnoreDepConfigValue(value) {
95
+ return Object.keys(IDependencySection).includes(value);
96
+ }
97
+
98
+ //#endregion
99
+ //#region src/package-source.ts
100
+ function createPackageSource() {
101
+ return { fetch: async (name) => {
102
+ const response = await fetch(encodeURI(name)).catch((err) => {
103
+ if (err.statusCode === 404) return null;
104
+ throw err;
105
+ });
106
+ const data = await response?.json();
107
+ if (!data?.versions) return null;
108
+ const versionIdentifiers = Object.keys(data.versions).sort(compare).reverse();
109
+ const versions = versionIdentifiers.map((v) => {
110
+ const item = data.versions[v];
111
+ return {
112
+ version: item.version,
113
+ containsInternalTypings: !!item.types || !!item.typings
114
+ };
115
+ });
116
+ return {
117
+ name: data.name,
118
+ deprecated: Boolean(data.versions[versionIdentifiers[0]].deprecated),
119
+ latestVersion: data["dist-tags"].latest,
120
+ versions
121
+ };
122
+ } };
123
+ }
124
+
125
+ //#endregion
126
+ //#region src/versioning.ts
127
+ function getClosestMatchingVersion(availableVersions, version) {
128
+ const parsedVersion = parseVersion(version);
129
+ if (!parsedVersion) return availableVersions[0];
130
+ const bestMatch = availableVersions.find((v) => {
131
+ const parsedAvailableVersion = parseVersion(v.version);
132
+ if (!parsedAvailableVersion) return false;
133
+ if (parsedVersion.major !== parsedAvailableVersion.major) return false;
134
+ if (parsedVersion.minor !== parsedAvailableVersion.minor) return false;
135
+ return true;
136
+ });
137
+ return bestMatch ?? availableVersions[0];
138
+ }
139
+ /**
140
+ * Parses the version if possible.
141
+ *
142
+ * @param version
143
+ * @returns
144
+ */
145
+ function parseVersion(version) {
146
+ return parse(cleanVersion(version));
147
+ }
148
+ /**
149
+ * Cleans the version of any semver range specifiers.
150
+ * @param version
151
+ * @returns
152
+ */
153
+ function cleanVersion(version) {
154
+ return version.replace(/^[\^~=\s]/, "");
155
+ }
156
+
157
+ //#endregion
158
+ //#region src/type-syncer.ts
159
+ function createTypeSyncer(packageJSONService, workspaceResolverService, packageSource, configService, globber) {
160
+ const fetchPackageInfo = memoizeAsync(packageSource.fetch);
161
+ return { sync };
162
+ /**
163
+ * Syncs typings in the specified package.json.
164
+ */
165
+ async function sync(filePath, flags) {
166
+ const dryRun = !!flags.dry;
167
+ const syncOpts = await configService.readConfig(filePath, flags);
168
+ const { file, subManifests } = await getManifests(filePath, globber, syncOpts.ignoreProjects ?? []);
169
+ const syncedFiles = await Promise.all([syncFile(filePath, file, syncOpts, dryRun), ...subManifests.map(async (p) => syncFile(p, await packageJSONService.readPackageFile(p), syncOpts, dryRun))]);
170
+ return { syncedFiles };
171
+ }
172
+ /**
173
+ * Get the `package.json` files and sub-packages.
174
+ *
175
+ * @param filePath
176
+ * @param globber
177
+ */
178
+ async function getManifests(filePath, globber$1, ignoredWorkspaces) {
179
+ const file = await packageJSONService.readPackageFile(filePath);
180
+ const subPackages = await workspaceResolverService.getWorkspaces(file, path.dirname(filePath), globber$1, ignoredWorkspaces);
181
+ const subManifests = subPackages.map((p) => path.join(p, "package.json"));
182
+ return {
183
+ file,
184
+ subManifests
185
+ };
186
+ }
187
+ /**
188
+ * Syncs a single file.
189
+ *
190
+ * @param filePath
191
+ * @param file
192
+ * @param allTypings
193
+ * @param opts
194
+ */
195
+ async function syncFile(filePath, file, opts, dryRun) {
196
+ const { ignoreDeps, ignorePackages } = opts;
197
+ const allLocalPackages = Object.values(IDependencySection).map((dep) => {
198
+ const section = getDependenciesBySection(file, dep);
199
+ if (!section) return [];
200
+ const ignoredSection = ignoreDeps?.includes(dep);
201
+ return getPackagesFromSection(section, ignoredSection, ignorePackages);
202
+ }).flat();
203
+ const allPackageNames = uniq(allLocalPackages.map((p) => p.name));
204
+ const potentiallyUntypedPackages = getPotentiallyUntypedPackages(allPackageNames);
205
+ const used = [];
206
+ const devDepsToAdd = await Promise.all(potentiallyUntypedPackages.map(async (t) => {
207
+ const typePackageInfoPromise = fetchPackageInfo(t.typesPackageName);
208
+ const codePackageInfo = await fetchPackageInfo(t.codePackageName);
209
+ if (!codePackageInfo) return {};
210
+ const localCodePackage = allLocalPackages.find((p) => p.name === t.codePackageName);
211
+ const closestMatchingCodeVersion = getClosestMatchingVersion(codePackageInfo.versions, localCodePackage.version);
212
+ if (closestMatchingCodeVersion.containsInternalTypings) return {};
213
+ const typePackageInfo = await typePackageInfoPromise;
214
+ if (!typePackageInfo || typePackageInfo.deprecated) return {};
215
+ const closestMatchingTypingsVersion = getClosestMatchingVersion(typePackageInfo.versions, localCodePackage.version);
216
+ const version = closestMatchingTypingsVersion.version;
217
+ const semverRangeSpecifier = "~";
218
+ used.push(t);
219
+ return { [t.typesPackageName]: semverRangeSpecifier + version };
220
+ })).then(mergeObjects);
221
+ const devDeps = file.devDependencies;
222
+ if (!dryRun) {
223
+ const newPackageFile = { ...file };
224
+ if (Object.keys(devDepsToAdd).length > 0) {
225
+ newPackageFile.devDependencies = orderObject({
226
+ ...devDepsToAdd,
227
+ ...devDeps
228
+ });
229
+ await packageJSONService.writePackageFile(filePath, newPackageFile);
230
+ }
231
+ }
232
+ return {
233
+ filePath,
234
+ newTypings: used,
235
+ package: file
236
+ };
237
+ }
238
+ }
239
+ /**
240
+ * Returns an array of packages that do not have a `@types/` package.
241
+ *
242
+ * @param allPackageNames Used to filter the typings that are new.
243
+ * @param allTypings All typings available
244
+ */
245
+ function getPotentiallyUntypedPackages(allPackageNames) {
246
+ const existingTypings = allPackageNames.filter((x) => x.startsWith("@types/"));
247
+ return allPackageNames.flatMap((p) => {
248
+ if (p.startsWith("@types/")) return [];
249
+ const typingsName = getTypingsName(p);
250
+ const fullTypingsPackage = typed(p);
251
+ const alreadyHasTyping = existingTypings.includes(fullTypingsPackage);
252
+ if (alreadyHasTyping) return [];
253
+ return [{
254
+ typingsName,
255
+ typesPackageName: fullTypingsPackage,
256
+ codePackageName: p
257
+ }];
258
+ });
259
+ }
260
+ /**
261
+ * Gets the typings name for the specified package name.
262
+ * For example, `koa` would be `koa`, but `@koa/router` would be `koa__router`.
263
+ *
264
+ * @param packageName the package name to generate the typings name for
265
+ */
266
+ function getTypingsName(packageName) {
267
+ const scopeInfo = getPackageScope(packageName);
268
+ return scopeInfo && scopeInfo[0] !== "types" ? `${scopeInfo[0]}__${scopeInfo[1]}` : packageName;
269
+ }
270
+ /**
271
+ * If a package is scoped, returns the scope + package as a tuple, otherwise null.
272
+ *
273
+ * @param packageName Package name to check scope for.
274
+ */
275
+ function getPackageScope(packageName) {
276
+ const EXPR = /^@([^/]+)\/(.*)$/i;
277
+ const matches = EXPR.exec(packageName);
278
+ if (!matches) return null;
279
+ return [matches[1], matches[2]];
280
+ }
281
+ /**
282
+ * Get packages from a dependency section
283
+ *
284
+ * @param section
285
+ * @param ignoredSection
286
+ * @param ignorePackages
287
+ */
288
+ function getPackagesFromSection(section, ignoredSection, ignorePackages) {
289
+ return Object.keys(section).flatMap((name) => {
290
+ const isTyping = name.startsWith("@types/");
291
+ if (!isTyping) {
292
+ if (ignoredSection || ignorePackages?.includes(name)) return [];
293
+ }
294
+ return [{
295
+ name,
296
+ version: section[name]
297
+ }];
298
+ });
299
+ }
300
+ /**
301
+ * Get dependencies from a package section
302
+ *
303
+ * @param file Package file
304
+ * @param section Package section, eg: dev, peer
305
+ */
306
+ function getDependenciesBySection(file, section) {
307
+ const dependenciesSection = (() => {
308
+ switch (section) {
309
+ case IDependencySection.deps: return file.dependencies;
310
+ case IDependencySection.dev: return file.devDependencies;
311
+ case IDependencySection.optional: return file.optionalDependencies;
312
+ case IDependencySection.peer: return file.peerDependencies;
313
+ }
314
+ })();
315
+ return dependenciesSection;
316
+ }
317
+
318
+ //#endregion
319
+ export { IDependencySection, createConfigService, createPackageSource, createTypeSyncer, ensureWorkspacesArray, uniq };
320
+ //# sourceMappingURL=type-syncer-C_rkDNfx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-syncer-C_rkDNfx.js","names":["source: Array<T>","source: T","object: Partial<T>","name: string","comparer?: (a: string, b: string) => number","result: Record<string, U>","fn: (...args: U) => Promise<V>","data?: IWorkspacesSection","filePath: string","flags: ICLIArguments['flags']","fileConfig: ISyncOptions","key: string","validator?: (value: string) => boolean","value: string","availableVersions: Array<IPackageVersionInfo>","version: string","packageJSONService: IPackageJSONService","workspaceResolverService: IWorkspaceResolverService","packageSource: IPackageSource","configService: IConfigService","globber: IGlobber","filePath: string","flags: ICLIArguments['flags']","syncedFiles: Array<ISyncedFile>","ignoredWorkspaces: IWorkspacesArray","globber","file: IPackageFile","opts: ISyncOptions","dryRun: boolean","used: ReturnType<typeof getPotentiallyUntypedPackages>","newPackageFile: IPackageFile","allPackageNames: Array<string>","packageName: string","section: IDependenciesSection","ignoredSection?: boolean","ignorePackages?: Array<string>","section: IDependencySection"],"sources":["../src/types.ts","../src/util.ts","../src/config-service.ts","../src/package-source.ts","../src/versioning.ts","../src/type-syncer.ts"],"sourcesContent":["import type { IWorkspacesArray, IWorkspacesSection } from './workspace-resolver'\n\n/**\n * The guts of the program.\n */\nexport interface ITypeSyncer {\n sync(\n this: void,\n filePath: string,\n flags: ICLIArguments['flags'],\n ): Promise<ISyncResult>\n}\n\n/**\n * Sync options.\n */\nexport interface ISyncOptions {\n /**\n * Ignore certain deps.\n */\n ignoreDeps?: Array<IDependencySection>\n\n /**\n * Ignore certain packages.\n */\n ignorePackages?: Array<string>\n\n /**\n * Skip resolution of certain projects in the workspace.\n */\n ignoreProjects?: IWorkspacesArray\n}\n\n/**\n * Package.json file.\n */\nexport interface IPackageFile {\n name?: string\n dependencies?: IDependenciesSection\n devDependencies?: IDependenciesSection\n peerDependencies?: IDependenciesSection\n optionalDependencies?: IDependenciesSection\n workspaces?: IWorkspacesSection\n [key: string]: unknown\n}\n\n/**\n * Section in package.json representing dependencies.\n */\nexport type IDependenciesSection = Record<string, string>\n\n/**\n * Package + version record, collected from the {\"package\": \"^1.2.3\"} sections.\n */\nexport interface IPackageVersion {\n name: string\n version: string\n}\n\n/**\n * Describes how a package may be typed.\n */\nexport interface IPackageTypingDescriptor {\n typingsName: string\n codePackageName: string\n typesPackageName: string\n}\n\n/**\n * A type definition with the corresponding code package name.\n */\nexport interface ISyncedTypeDefinition extends IPackageTypingDescriptor {\n codePackageName: string\n}\n\n/**\n * Sync result.\n */\nexport interface ISyncResult {\n /**\n * The files that were synced.\n */\n syncedFiles: Array<ISyncedFile>\n}\n\n/**\n * A file that was synced.\n */\nexport interface ISyncedFile {\n /**\n * The cwd-relative path to the synced file.\n */\n filePath: string\n /**\n * The package file that was synced.\n */\n package: IPackageFile\n /**\n * The new typings that were added.\n */\n newTypings: Array<ISyncedTypeDefinition>\n}\n\n/**\n * Dependency sections.\n */\nexport enum IDependencySection {\n dev = 'dev',\n deps = 'deps',\n optional = 'optional',\n peer = 'peer',\n}\n\n/**\n * CLI arguments.\n */\nexport interface ICLIArguments {\n flags: Record<string, boolean | string | undefined>\n args: Array<string>\n}\n","import type { IWorkspacesArray, IWorkspacesSection } from './workspace-resolver'\n\n/**\n * Returns unique items.\n *\n * @param source The source to filter\n */\nexport function uniq<T>(source: Array<T>): Array<T> {\n return [...new Set(source)]\n}\n\n/**\n * Remove blank attributes in a object.\n *\n * @param source\n */\nexport function shrinkObject<T extends object>(source: T): Partial<T> {\n const object: Partial<T> = {}\n\n for (const key in source) {\n if (source[key] !== undefined) {\n object[key] = source[key]\n }\n }\n\n return object\n}\n\n/**\n * Merges a sequence of objects into a single object using `reduce`.\n *\n * @param source An array of objects to merge.\n */\nexport function mergeObjects<T>(source: Array<T>): T {\n return source.reduce((accum, next) => ({ ...accum, ...next }), {} as T)\n}\n\n/**\n * Returns the assumed types package name.\n * @param name Package name\n */\nexport function typed(name: string): string {\n // If the package is scoped, the typings scheme is slightly different.\n if (/^@.*?\\//i.test(name)) {\n const splat = name.split('/')\n return `@types/${splat[0].slice(1)}__${splat[1]}`\n }\n\n return `@types/${name}`\n}\n\n/**\n * Returns the assumed code package name based on a types package name.\n * @param name\n */\nexport function untyped(name: string): string {\n const prefix = '@types/'\n if (!name.startsWith(prefix)) {\n return name\n }\n name = name.substring(prefix.length)\n const splat = name.split('__')\n if (splat.length === 2) {\n return `@${splat[0]}/${splat[1]}`\n }\n return name\n}\n\n/**\n * Orders an object.\n * @param source\n */\nexport function orderObject<T extends Record<string | number | symbol, U>, U>(\n source: T,\n comparer?: (a: string, b: string) => number,\n): T {\n const keys = Object.keys(source).sort(comparer)\n const result: Record<string, U> = {}\n for (const key of keys) {\n result[key] = source[key]\n }\n\n return result as T\n}\n\n/**\n * Async memoize.\n *\n * @param fn\n */\nexport function memoizeAsync<U extends Array<W>, V, W>(\n fn: (...args: U) => Promise<V>,\n) {\n const cache = new Map<W, Promise<V>>()\n\n async function run(...args: U): Promise<V> {\n try {\n return await fn(...args)\n } catch (err) {\n cache.delete(args[0])\n throw err\n }\n }\n\n return async function (...args: U): Promise<V> {\n const key = args[0]\n if (cache.has(key)) {\n return cache.get(key)!\n }\n\n const p = run(...args)\n cache.set(key, p)\n return p\n }\n}\n\n/**\n * Ensures that we have a valid workspaces array.\n *\n * @param data\n */\nexport function ensureWorkspacesArray(\n data?: IWorkspacesSection,\n): IWorkspacesArray {\n if (!data) {\n return []\n }\n\n if (!Array.isArray(data)) {\n return ensureWorkspacesArray(data.packages)\n }\n\n if (!data.every((s) => typeof s === 'string')) {\n return []\n }\n\n return data\n}\n","import * as path from 'node:path'\nimport { cosmiconfig } from 'cosmiconfig'\nimport {\n type ICLIArguments,\n IDependencySection,\n type ISyncOptions,\n} from './types'\nimport { shrinkObject } from './util'\n\n/**\n * Config Service.\n */\nexport interface IConfigService {\n /**\n * Get typesync config.\n */\n readConfig(\n this: void,\n filePath: string,\n flags: ICLIArguments['flags'],\n ): Promise<ISyncOptions>\n}\n\nconst explorer = cosmiconfig('typesync')\n\nexport function createConfigService(): IConfigService {\n return {\n readConfig: async (filePath: string, flags: ICLIArguments['flags']) => {\n const fileConfig: ISyncOptions = await explorer\n .search(path.dirname(filePath))\n .then((result) => /* v8 ignore next */ result?.config ?? {})\n\n const cliConfig = readCliConfig(flags)\n\n return { ...shrinkObject(fileConfig), ...shrinkObject(cliConfig) }\n },\n }\n}\n\nfunction readCliConfig(flags: ICLIArguments['flags']): ISyncOptions {\n const readValues = <T extends string>(\n key: string,\n validator?: (value: string) => boolean,\n ): Array<T> | undefined => {\n const values = flags[key]\n return typeof values === 'string'\n ? values\n .split(',')\n .filter((value): value is T => (validator ? validator(value) : true))\n : undefined\n }\n\n return {\n ignoreDeps: readValues('ignoredeps', isIgnoreDepConfigValue),\n ignorePackages: readValues('ignorepackages'),\n ignoreProjects: readValues('ignoreprojects'),\n }\n}\n\nfunction isIgnoreDepConfigValue(value: string): value is IDependencySection {\n return Object.keys(IDependencySection).includes(value)\n}\n","import fetch from 'npm-registry-fetch'\nimport { compare } from 'semver'\nimport type { IPackageVersionInfo } from './versioning'\n\n/**\n * Fetches info about a package.\n */\nexport interface IPackageSource {\n /**\n * Fetches package info from an external source.\n *\n * @param packageName\n */\n fetch(this: void, packageName: string): Promise<IPackageInfo | null>\n}\n\n/**\n * Interface for the Package Info structure.\n */\nexport interface IPackageInfo {\n name: string\n latestVersion: string\n deprecated: boolean\n versions: Array<IPackageVersionInfo>\n}\n\n/**\n * Creates a package source.\n */\nexport function createPackageSource(): IPackageSource {\n return {\n /**\n * Fetches info about a package, or `null` if not found.\n */\n fetch: async (name) => {\n const response = await fetch(encodeURI(name)).catch((err) => {\n if (err.statusCode === 404) {\n return null\n /* v8 ignore next */\n }\n\n /* v8 ignore next */\n throw err\n })\n\n const data = await response?.json()\n\n if (!data?.versions) {\n return null\n }\n\n const versionIdentifiers = Object.keys(data.versions)\n .sort(compare)\n .reverse()\n const versions = versionIdentifiers.map<IPackageVersionInfo>((v) => {\n const item = data.versions[v]\n return {\n version: item.version,\n containsInternalTypings: !!item.types || !!item.typings,\n }\n })\n\n return {\n name: data.name,\n deprecated: Boolean(data.versions[versionIdentifiers[0]].deprecated),\n latestVersion: data['dist-tags'].latest,\n // Sort by version, highest version first.\n versions: versions,\n }\n },\n }\n}\n","import { parse } from 'semver'\n\n/**\n * Version descriptor for versions returned in remote package info.\n */\nexport interface IPackageVersionInfo {\n version: string\n containsInternalTypings: boolean\n}\n\n/**\n * Gets the closest matching package version info.\n *\n * @param availableVersions\n * @param version\n */\nexport function getClosestMatchingVersion(\n availableVersions: Array<IPackageVersionInfo>,\n version: string,\n): IPackageVersionInfo {\n const parsedVersion = parseVersion(version)\n if (!parsedVersion) {\n return availableVersions[0]\n }\n\n const bestMatch = availableVersions.find((v) => {\n const parsedAvailableVersion = parseVersion(v.version)\n if (!parsedAvailableVersion) {\n return false\n }\n\n if (parsedVersion.major !== parsedAvailableVersion.major) {\n return false\n }\n\n if (parsedVersion.minor !== parsedAvailableVersion.minor) {\n return false\n }\n\n return true\n })\n\n return bestMatch ?? availableVersions[0]\n}\n\n/**\n * Parses the version if possible.\n *\n * @param version\n * @returns\n */\nfunction parseVersion(version: string) {\n return parse(cleanVersion(version))\n}\n\n/**\n * Cleans the version of any semver range specifiers.\n * @param version\n * @returns\n */\nfunction cleanVersion(version: string) {\n return version.replace(/^[\\^~=\\s]/, '')\n}\n","import * as path from 'node:path'\nimport type { IConfigService } from './config-service'\nimport type { IGlobber } from './globber'\nimport type { IPackageJSONService } from './package-json-file-service'\nimport type { IPackageSource } from './package-source'\nimport {\n type ICLIArguments,\n type IDependenciesSection,\n IDependencySection,\n type IPackageFile,\n type IPackageTypingDescriptor,\n type IPackageVersion,\n type ISyncOptions,\n type ISyncResult,\n type ISyncedFile,\n type ITypeSyncer,\n} from './types'\nimport { memoizeAsync, mergeObjects, orderObject, typed, uniq } from './util'\nimport { getClosestMatchingVersion } from './versioning'\nimport type {\n IWorkspaceResolverService,\n IWorkspacesArray,\n} from './workspace-resolver'\n\n/**\n * Creates a type syncer.\n *\n * @param packageJSONservice\n * @param typeDefinitionSource\n */\nexport function createTypeSyncer(\n packageJSONService: IPackageJSONService,\n workspaceResolverService: IWorkspaceResolverService,\n packageSource: IPackageSource,\n configService: IConfigService,\n globber: IGlobber,\n): ITypeSyncer {\n const fetchPackageInfo = memoizeAsync(packageSource.fetch)\n\n return {\n sync,\n }\n\n /**\n * Syncs typings in the specified package.json.\n */\n async function sync(\n filePath: string,\n flags: ICLIArguments['flags'],\n ): Promise<ISyncResult> {\n const dryRun = !!flags.dry\n const syncOpts = await configService.readConfig(filePath, flags)\n const { file, subManifests } = await getManifests(\n filePath,\n globber,\n syncOpts.ignoreProjects ?? [],\n )\n\n const syncedFiles: Array<ISyncedFile> = await Promise.all([\n syncFile(filePath, file, syncOpts, dryRun),\n ...subManifests.map(async (p) =>\n syncFile(\n p,\n await packageJSONService.readPackageFile(p),\n syncOpts,\n dryRun,\n ),\n ),\n ])\n\n return {\n syncedFiles,\n }\n }\n\n /**\n * Get the `package.json` files and sub-packages.\n *\n * @param filePath\n * @param globber\n */\n async function getManifests(\n filePath: string,\n globber: IGlobber,\n ignoredWorkspaces: IWorkspacesArray,\n ) {\n const file = await packageJSONService.readPackageFile(filePath)\n const subPackages = await workspaceResolverService.getWorkspaces(\n file,\n path.dirname(filePath),\n globber,\n ignoredWorkspaces,\n )\n const subManifests = subPackages.map((p) => path.join(p, 'package.json'))\n\n return {\n file,\n subManifests,\n }\n }\n\n /**\n * Syncs a single file.\n *\n * @param filePath\n * @param file\n * @param allTypings\n * @param opts\n */\n async function syncFile(\n filePath: string,\n file: IPackageFile,\n opts: ISyncOptions,\n dryRun: boolean,\n ): Promise<ISyncedFile> {\n const { ignoreDeps, ignorePackages } = opts\n\n const allLocalPackages = Object.values(IDependencySection)\n .map((dep) => {\n const section = getDependenciesBySection(file, dep)\n if (!section) return []\n\n const ignoredSection = ignoreDeps?.includes(dep)\n return getPackagesFromSection(section, ignoredSection, ignorePackages)\n })\n .flat()\n const allPackageNames = uniq(allLocalPackages.map((p) => p.name))\n const potentiallyUntypedPackages =\n getPotentiallyUntypedPackages(allPackageNames)\n\n // This is pushed to in the inner `map`, because packages that have DT-typings\n // *as well* as internal typings should be excluded.\n const used: ReturnType<typeof getPotentiallyUntypedPackages> = []\n const devDepsToAdd = await Promise.all(\n potentiallyUntypedPackages.map(async (t) => {\n // Fetch the code package from the source.\n const typePackageInfoPromise = fetchPackageInfo(t.typesPackageName)\n const codePackageInfo = await fetchPackageInfo(t.codePackageName)\n\n // If the code package was not found, there's nothing else to do.\n if (!codePackageInfo) {\n return {}\n }\n\n const localCodePackage = allLocalPackages.find(\n (p) => p.name === t.codePackageName,\n )!\n\n // Find the closest matching code package version relative to what's in our package.json\n const closestMatchingCodeVersion = getClosestMatchingVersion(\n codePackageInfo.versions,\n localCodePackage.version,\n )\n\n // If the closest matching version contains internal typings, don't include it.\n if (closestMatchingCodeVersion.containsInternalTypings) {\n return {}\n }\n\n // Look for the closest matching typings package.\n const typePackageInfo = await typePackageInfoPromise\n\n // If the types package was not found, or if it was deprecated, there's nothing else to do.\n if (!typePackageInfo || typePackageInfo.deprecated) {\n return {}\n }\n\n // Gets the closest matching typings version, or the newest one.\n const closestMatchingTypingsVersion = getClosestMatchingVersion(\n typePackageInfo.versions,\n localCodePackage.version,\n )\n\n const version = closestMatchingTypingsVersion.version\n const semverRangeSpecifier = '~'\n used.push(t)\n return {\n [t.typesPackageName]: semverRangeSpecifier + version,\n }\n }),\n ).then(mergeObjects)\n const devDeps = file.devDependencies\n if (!dryRun) {\n const newPackageFile: IPackageFile = { ...file }\n\n if (Object.keys(devDepsToAdd).length > 0) {\n newPackageFile.devDependencies = orderObject({\n ...devDepsToAdd,\n ...devDeps,\n })\n\n await packageJSONService.writePackageFile(filePath, newPackageFile)\n }\n }\n\n return {\n filePath,\n newTypings: used,\n package: file,\n }\n }\n}\n\n/**\n * Returns an array of packages that do not have a `@types/` package.\n *\n * @param allPackageNames Used to filter the typings that are new.\n * @param allTypings All typings available\n */\nfunction getPotentiallyUntypedPackages(\n allPackageNames: Array<string>,\n): Array<IPackageTypingDescriptor> {\n const existingTypings = allPackageNames.filter((x) => x.startsWith('@types/'))\n\n return allPackageNames.flatMap((p) => {\n // Ignore typings packages themselves.\n if (p.startsWith('@types/')) {\n return []\n }\n\n const typingsName = getTypingsName(p)\n const fullTypingsPackage = typed(p)\n const alreadyHasTyping = existingTypings.includes(fullTypingsPackage)\n if (alreadyHasTyping) {\n return []\n }\n\n return [\n {\n typingsName: typingsName,\n typesPackageName: fullTypingsPackage,\n codePackageName: p,\n },\n ]\n })\n}\n\n/**\n * Gets the typings name for the specified package name.\n * For example, `koa` would be `koa`, but `@koa/router` would be `koa__router`.\n *\n * @param packageName the package name to generate the typings name for\n */\nfunction getTypingsName(packageName: string) {\n const scopeInfo = getPackageScope(packageName)\n\n return scopeInfo && scopeInfo[0] !== 'types'\n ? `${scopeInfo[0]}__${scopeInfo[1]}`\n : packageName\n}\n\n/**\n * If a package is scoped, returns the scope + package as a tuple, otherwise null.\n *\n * @param packageName Package name to check scope for.\n */\nfunction getPackageScope(packageName: string): [string, string] | null {\n const EXPR = /^@([^/]+)\\/(.*)$/i\n const matches = EXPR.exec(packageName)\n if (!matches) {\n return null\n }\n\n return [matches[1], matches[2]]\n}\n\n/**\n * Get packages from a dependency section\n *\n * @param section\n * @param ignoredSection\n * @param ignorePackages\n */\nfunction getPackagesFromSection(\n section: IDependenciesSection,\n ignoredSection?: boolean,\n ignorePackages?: Array<string>,\n): Array<IPackageVersion> {\n return Object.keys(section).flatMap((name) => {\n const isTyping = name.startsWith('@types/')\n\n // Never ignore `@types` packages.\n if (!isTyping) {\n // If it's not a `@types` package, check whether the section or package is ignored.\n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- We want to check for false as well.\n if (ignoredSection || ignorePackages?.includes(name)) {\n return []\n }\n }\n\n return [{ name, version: section[name] }]\n })\n}\n\n/**\n * Get dependencies from a package section\n *\n * @param file Package file\n * @param section Package section, eg: dev, peer\n */\nfunction getDependenciesBySection(\n file: IPackageFile,\n section: IDependencySection,\n): IDependenciesSection | undefined {\n const dependenciesSection = (() => {\n switch (section) {\n case IDependencySection.deps:\n return file.dependencies\n case IDependencySection.dev:\n return file.devDependencies\n case IDependencySection.optional:\n return file.optionalDependencies\n case IDependencySection.peer:\n return file.peerDependencies\n }\n })()\n return dependenciesSection\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { IConfigService } from "./config-service.js";
2
+ import type { IGlobber } from "./globber.js";
3
+ import type { IPackageJSONService } from "./package-json-file-service.js";
4
+ import type { IPackageSource } from "./package-source.js";
5
+ import { type ITypeSyncer } from "./types.js";
6
+ import type { IWorkspaceResolverService } from "./workspace-resolver.js";
7
+ /**
8
+ * Creates a type syncer.
9
+ *
10
+ * @param packageJSONservice
11
+ * @param typeDefinitionSource
12
+ */
13
+ export declare function createTypeSyncer(packageJSONService: IPackageJSONService, workspaceResolverService: IWorkspaceResolverService, packageSource: IPackageSource, configService: IConfigService, globber: IGlobber): ITypeSyncer;
@@ -0,0 +1,103 @@
1
+ import type { IWorkspacesArray, IWorkspacesSection } from "./workspace-resolver.js";
2
+ /**
3
+ * The guts of the program.
4
+ */
5
+ export interface ITypeSyncer {
6
+ sync(this: void, filePath: string, flags: ICLIArguments["flags"]): Promise<ISyncResult>;
7
+ }
8
+ /**
9
+ * Sync options.
10
+ */
11
+ export interface ISyncOptions {
12
+ /**
13
+ * Ignore certain deps.
14
+ */
15
+ ignoreDeps?: Array<IDependencySection>;
16
+ /**
17
+ * Ignore certain packages.
18
+ */
19
+ ignorePackages?: Array<string>;
20
+ /**
21
+ * Skip resolution of certain projects in the workspace.
22
+ */
23
+ ignoreProjects?: IWorkspacesArray;
24
+ }
25
+ /**
26
+ * Package.json file.
27
+ */
28
+ export interface IPackageFile {
29
+ name?: string;
30
+ dependencies?: IDependenciesSection;
31
+ devDependencies?: IDependenciesSection;
32
+ peerDependencies?: IDependenciesSection;
33
+ optionalDependencies?: IDependenciesSection;
34
+ workspaces?: IWorkspacesSection;
35
+ [key: string]: unknown;
36
+ }
37
+ /**
38
+ * Section in package.json representing dependencies.
39
+ */
40
+ export type IDependenciesSection = Record<string, string>;
41
+ /**
42
+ * Package + version record, collected from the {"package": "^1.2.3"} sections.
43
+ */
44
+ export interface IPackageVersion {
45
+ name: string;
46
+ version: string;
47
+ }
48
+ /**
49
+ * Describes how a package may be typed.
50
+ */
51
+ export interface IPackageTypingDescriptor {
52
+ typingsName: string;
53
+ codePackageName: string;
54
+ typesPackageName: string;
55
+ }
56
+ /**
57
+ * A type definition with the corresponding code package name.
58
+ */
59
+ export interface ISyncedTypeDefinition extends IPackageTypingDescriptor {
60
+ codePackageName: string;
61
+ }
62
+ /**
63
+ * Sync result.
64
+ */
65
+ export interface ISyncResult {
66
+ /**
67
+ * The files that were synced.
68
+ */
69
+ syncedFiles: Array<ISyncedFile>;
70
+ }
71
+ /**
72
+ * A file that was synced.
73
+ */
74
+ export interface ISyncedFile {
75
+ /**
76
+ * The cwd-relative path to the synced file.
77
+ */
78
+ filePath: string;
79
+ /**
80
+ * The package file that was synced.
81
+ */
82
+ package: IPackageFile;
83
+ /**
84
+ * The new typings that were added.
85
+ */
86
+ newTypings: Array<ISyncedTypeDefinition>;
87
+ }
88
+ /**
89
+ * Dependency sections.
90
+ */
91
+ export declare enum IDependencySection {
92
+ dev = "dev",
93
+ deps = "deps",
94
+ optional = "optional",
95
+ peer = "peer",
96
+ }
97
+ /**
98
+ * CLI arguments.
99
+ */
100
+ export interface ICLIArguments {
101
+ flags: Record<string, boolean | string | undefined>;
102
+ args: Array<string>;
103
+ }
package/dist/util.d.ts ADDED
@@ -0,0 +1,53 @@
1
+ import type { IWorkspacesArray, IWorkspacesSection } from "./workspace-resolver.js";
2
+ /**
3
+ * Returns unique items.
4
+ *
5
+ * @param source The source to filter
6
+ */
7
+ export declare function uniq<T>(source: Array<T>): Array<T>;
8
+ /**
9
+ * Remove blank attributes in a object.
10
+ *
11
+ * @param source
12
+ */
13
+ export declare function shrinkObject<T extends object>(source: T): Partial<T>;
14
+ /**
15
+ * Merges a sequence of objects into a single object using `reduce`.
16
+ *
17
+ * @param source An array of objects to merge.
18
+ */
19
+ export declare function mergeObjects<T>(source: Array<T>): T;
20
+ /**
21
+ * Returns the assumed types package name.
22
+ * @param name Package name
23
+ */
24
+ export declare function typed(name: string): string;
25
+ /**
26
+ * Returns the assumed code package name based on a types package name.
27
+ * @param name
28
+ */
29
+ export declare function untyped(name: string): string;
30
+ /**
31
+ * Orders an object.
32
+ * @param source
33
+ */
34
+ export declare function orderObject<
35
+ T extends Record<string | number | symbol, U>,
36
+ U
37
+ >(source: T, comparer?: (a: string, b: string) => number): T;
38
+ /**
39
+ * Async memoize.
40
+ *
41
+ * @param fn
42
+ */
43
+ export declare function memoizeAsync<
44
+ U extends Array<W>,
45
+ V,
46
+ W
47
+ >(fn: (...args: U) => Promise<V>): (...args: U) => Promise<V>;
48
+ /**
49
+ * Ensures that we have a valid workspaces array.
50
+ *
51
+ * @param data
52
+ */
53
+ export declare function ensureWorkspacesArray(data?: IWorkspacesSection): IWorkspacesArray;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Version descriptor for versions returned in remote package info.
3
+ */
4
+ export interface IPackageVersionInfo {
5
+ version: string;
6
+ containsInternalTypings: boolean;
7
+ }
8
+ /**
9
+ * Gets the closest matching package version info.
10
+ *
11
+ * @param availableVersions
12
+ * @param version
13
+ */
14
+ export declare function getClosestMatchingVersion(availableVersions: Array<IPackageVersionInfo>, version: string): IPackageVersionInfo;
@@ -0,0 +1,75 @@
1
+ import type * as fsUtils from "./fs-utils.js";
2
+ import type { IGlobber } from "./globber.js";
3
+ import type { IPackageFile } from "./types.js";
4
+ /**
5
+ * Service for fetching monorepo workspaces in a standardized format agnostic of the package manager used.
6
+ * It is used to allow syncing all types in a workspace when run from the root of a monorepo.
7
+ */
8
+ export interface IWorkspaceResolverService {
9
+ /**
10
+ * Reads, parses, and normalizes a workspaces configuration from the following files, in this order:
11
+ * - `package.json` `workspaces` field, as an array of globs.
12
+ * - `package.json` `workspaces` field, as an object with a `packages` field, which is an array of globs.
13
+ * - `pnpm-workspace.yaml` `packages` field, as an array of globs.
14
+ *
15
+ * Path is relative to the current working directory.
16
+ * Note that this returns a list of directories, not paths to the manifests themselves.
17
+ */
18
+ getWorkspaces(this: void, packageJson: IPackageFile, root: string, globber: IGlobber, ignored: IWorkspacesArray): Promise<IWorkspacesArray>;
19
+ }
20
+ /**
21
+ * @example
22
+ * ```json
23
+ * "workspaces": [
24
+ * "packages/*",
25
+ * ]
26
+ * ```
27
+ */
28
+ export type IWorkspacesArray = Array<string>;
29
+ /**
30
+ * @example
31
+ * ```yaml
32
+ * packages:
33
+ * - 'packages/*'
34
+ * ```
35
+ */
36
+ export interface IWorkspacesObject {
37
+ packages?: IWorkspacesArray;
38
+ }
39
+ /**
40
+ * @see {@link IWorkspacesArray}
41
+ */
42
+ export type NpmWorkspacesConfig = IWorkspacesArray;
43
+ /**
44
+ * Yarn is a special snowflake.
45
+ *
46
+ * @example
47
+ * ```json
48
+ * "workspaces": {
49
+ * "packages": [
50
+ * "packages/*",
51
+ * ],
52
+ * "nohoist": []
53
+ * }
54
+ * ```
55
+ */
56
+ export type YarnWorkspacesConfig = IWorkspacesArray | (IWorkspacesObject & { nohoist?: Array<string> });
57
+ /**
58
+ * The contents of a `pnpm-workspace.yaml` file.
59
+ *
60
+ * @example
61
+ * ```yaml
62
+ * packages:
63
+ * - 'packages/*'
64
+ * ```
65
+ */
66
+ export type PnpmWorkspacesConfig = IWorkspacesObject;
67
+ /**
68
+ * @see {@link IWorkspacesArray}
69
+ */
70
+ export type BunWorkspacesConfig = IWorkspacesArray;
71
+ /**
72
+ * Section in `package.json` representing workspaces.
73
+ */
74
+ export type IWorkspacesSection = NpmWorkspacesConfig | YarnWorkspacesConfig | BunWorkspacesConfig;
75
+ export declare function createWorkspaceResolverService({ readFileContents }: { readFileContents: typeof fsUtils.readFileContents }): IWorkspaceResolverService;