mlcl 1.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 (195) hide show
  1. package/.eslintignore +31 -0
  2. package/.eslintrc.json +54 -0
  3. package/LICENSE +200 -0
  4. package/README.md +101 -0
  5. package/babel.config.json +10 -0
  6. package/build/API/authorization.js +107 -0
  7. package/build/API/client.js +11 -0
  8. package/build/API/index.js +8 -0
  9. package/build/API/molecule/index.js +11 -0
  10. package/build/API/molecule/types.js +6 -0
  11. package/build/API/resource/device/index.js +12 -0
  12. package/build/API/resource/device/types.js +6 -0
  13. package/build/API/resource/device/utilities/confirmSshKey.js +20 -0
  14. package/build/API/resource/device/utilities/index.js +7 -0
  15. package/build/API/resource/device/utilities/sendSshKey.js +64 -0
  16. package/build/API/resource/index.js +10 -0
  17. package/build/API/resource/molecule/index.js +12 -0
  18. package/build/API/resource/molecule/types.js +6 -0
  19. package/build/API/resource/molecule/utilities/getPlan.js +15 -0
  20. package/build/API/resource/molecule/utilities/index.js +6 -0
  21. package/build/API/resource/payment/index.js +9 -0
  22. package/build/API/resource/payment/plans.js +28 -0
  23. package/build/API/resource/payment/platform.js +7 -0
  24. package/build/API/resource/payment/platforms/apple/index.js +21 -0
  25. package/build/API/resource/payment/platforms/apple/plans/appleMonthly.js +17 -0
  26. package/build/API/resource/payment/platforms/apple/plans/appleYearly.js +18 -0
  27. package/build/API/resource/payment/platforms/apple/plans/index.js +7 -0
  28. package/build/API/resource/payment/platforms/google/index.js +21 -0
  29. package/build/API/resource/payment/platforms/google/plans/googleMonthly.js +17 -0
  30. package/build/API/resource/payment/platforms/google/plans/googleYearly.js +18 -0
  31. package/build/API/resource/payment/platforms/google/plans/index.js +7 -0
  32. package/build/API/resource/payment/platforms/index.js +8 -0
  33. package/build/API/resource/payment/platforms/stripe/index.js +25 -0
  34. package/build/API/resource/payment/platforms/stripe/plans/index.js +11 -0
  35. package/build/API/resource/payment/platforms/stripe/plans/stripeBusinessMolecule.js +21 -0
  36. package/build/API/resource/payment/platforms/stripe/plans/stripeMonthly.js +18 -0
  37. package/build/API/resource/payment/platforms/stripe/plans/stripeMonthlyMolecule.js +18 -0
  38. package/build/API/resource/payment/platforms/stripe/plans/stripeSingleUseMolecule.js +19 -0
  39. package/build/API/resource/payment/platforms/stripe/plans/stripeUnlimitedUseMolecule.js +19 -0
  40. package/build/API/resource/payment/platforms/stripe/plans/stripeYearly.js +19 -0
  41. package/build/API/resource/payment/types.js +6 -0
  42. package/build/API/resource/types.js +6 -0
  43. package/build/API/resource/user/index.js +15 -0
  44. package/build/API/resource/user/types.js +6 -0
  45. package/build/API/resource/user/utilities/getPlan.js +12 -0
  46. package/build/API/resource/user/utilities/index.js +7 -0
  47. package/build/API/resource/user/utilities/logIn.js +60 -0
  48. package/build/cli.js +15 -0
  49. package/build/commands/add-ssh-key.js +24 -0
  50. package/build/commands/buy.js +70 -0
  51. package/build/commands/clone.js +329 -0
  52. package/build/commands/index.js +17 -0
  53. package/build/commands/info.js +33 -0
  54. package/build/commands/login.js +20 -0
  55. package/build/commands/logout.js +23 -0
  56. package/build/commands/molecule/index.js +11 -0
  57. package/build/commands/molecule/types.js +6 -0
  58. package/build/commands/remove-ssh-key.js +36 -0
  59. package/build/commands/select.js +98 -0
  60. package/build/commands/set-api-key.js +73 -0
  61. package/build/commands/subscribe.js +74 -0
  62. package/build/commands/unsubscribe.js +59 -0
  63. package/build/commands/utilities/asyncExec.js +6 -0
  64. package/build/commands/utilities/branchExists.js +13 -0
  65. package/build/commands/utilities/branchExistsSync.js +12 -0
  66. package/build/commands/utilities/checkoutSelectionBranch.js +49 -0
  67. package/build/commands/utilities/cherryPick.js +20 -0
  68. package/build/commands/utilities/cloneRepo.js +9 -0
  69. package/build/commands/utilities/convertNpmToYarn.js +60 -0
  70. package/build/commands/utilities/convertTypeDocToJSDoc.js +51 -0
  71. package/build/commands/utilities/convertTypeScriptToJavaScript.js +451 -0
  72. package/build/commands/utilities/enableMergeDrivers.js +50 -0
  73. package/build/commands/utilities/getCurrentBranch.js +11 -0
  74. package/build/commands/utilities/getCurrentBranchSync.js +7 -0
  75. package/build/commands/utilities/getRepoRootPath.js +7 -0
  76. package/build/commands/utilities/getRepoRootPathSync.js +13 -0
  77. package/build/commands/utilities/index.js +16 -0
  78. package/build/commands/utilities/npm-to-yarn.js +41 -0
  79. package/build/commands/utilities/ts-to-js.js +344 -0
  80. package/build/commands/version.js +14 -0
  81. package/build/commands/x-merge-json.js +33 -0
  82. package/build/config.js +5 -0
  83. package/build/environment.js +80 -0
  84. package/build/index.js +23 -0
  85. package/build/logger.js +12 -0
  86. package/build/pkg.js +5 -0
  87. package/build/repoConfig copy.js +5 -0
  88. package/build/repoConfig.js +5 -0
  89. package/build/types/global.js +6 -0
  90. package/build/types/index.js +6 -0
  91. package/build/userConfig.js +5 -0
  92. package/build/utilities/__tests__/getErrorMessage.js +26 -0
  93. package/build/utilities/__tests__/timeAgo.js +39 -0
  94. package/build/utilities/checkVersion.js +29 -0
  95. package/build/utilities/getErrorMessage.js +15 -0
  96. package/build/utilities/index.js +13 -0
  97. package/build/utilities/readConfig.js +19 -0
  98. package/build/utilities/readRepoConfig copy.js +20 -0
  99. package/build/utilities/readRepoConfig.js +19 -0
  100. package/build/utilities/readUserConfig.js +20 -0
  101. package/build/utilities/synchronizeUserConfig.js +25 -0
  102. package/build/utilities/timeAgo.js +42 -0
  103. package/build/utilities/userLoggedIn.js +24 -0
  104. package/build/utilities/writeConfig.js +8 -0
  105. package/build/utilities/writeRepoConfig copy.js +9 -0
  106. package/build/utilities/writeRepoConfig.js +10 -0
  107. package/build/utilities/writeUserConfig.js +11 -0
  108. package/jest.config.json +11 -0
  109. package/package.json +56 -0
  110. package/src/API/authorization.ts +143 -0
  111. package/src/API/client.ts +12 -0
  112. package/src/API/index.ts +10 -0
  113. package/src/API/resource/device/index.ts +27 -0
  114. package/src/API/resource/device/types.ts +80 -0
  115. package/src/API/resource/device/utilities/confirmSshKey.ts +25 -0
  116. package/src/API/resource/device/utilities/index.ts +8 -0
  117. package/src/API/resource/device/utilities/sendSshKey.ts +80 -0
  118. package/src/API/resource/index.ts +12 -0
  119. package/src/API/resource/molecule/index.ts +30 -0
  120. package/src/API/resource/molecule/types.ts +332 -0
  121. package/src/API/resource/molecule/utilities/getPlan.ts +21 -0
  122. package/src/API/resource/molecule/utilities/index.ts +7 -0
  123. package/src/API/resource/payment/index.ts +12 -0
  124. package/src/API/resource/payment/plans.ts +32 -0
  125. package/src/API/resource/payment/platform.ts +11 -0
  126. package/src/API/resource/payment/platforms/apple/index.ts +25 -0
  127. package/src/API/resource/payment/platforms/apple/plans/appleMonthly.ts +19 -0
  128. package/src/API/resource/payment/platforms/apple/plans/appleYearly.ts +20 -0
  129. package/src/API/resource/payment/platforms/apple/plans/index.ts +9 -0
  130. package/src/API/resource/payment/platforms/google/index.ts +25 -0
  131. package/src/API/resource/payment/platforms/google/plans/googleMonthly.ts +19 -0
  132. package/src/API/resource/payment/platforms/google/plans/googleYearly.ts +20 -0
  133. package/src/API/resource/payment/platforms/google/plans/index.ts +9 -0
  134. package/src/API/resource/payment/platforms/index.ts +10 -0
  135. package/src/API/resource/payment/platforms/stripe/index.ts +29 -0
  136. package/src/API/resource/payment/platforms/stripe/plans/index.ts +12 -0
  137. package/src/API/resource/payment/platforms/stripe/plans/stripeBusinessMolecule.ts +23 -0
  138. package/src/API/resource/payment/platforms/stripe/plans/stripeMonthly.ts +20 -0
  139. package/src/API/resource/payment/platforms/stripe/plans/stripeMonthlyMolecule.ts +20 -0
  140. package/src/API/resource/payment/platforms/stripe/plans/stripeSingleUseMolecule.ts +21 -0
  141. package/src/API/resource/payment/platforms/stripe/plans/stripeUnlimitedUseMolecule.ts +21 -0
  142. package/src/API/resource/payment/platforms/stripe/plans/stripeYearly.ts +21 -0
  143. package/src/API/resource/payment/types.ts +201 -0
  144. package/src/API/resource/types.ts +169 -0
  145. package/src/API/resource/user/index.ts +29 -0
  146. package/src/API/resource/user/types.ts +131 -0
  147. package/src/API/resource/user/utilities/getPlan.ts +16 -0
  148. package/src/API/resource/user/utilities/index.ts +8 -0
  149. package/src/API/resource/user/utilities/logIn.ts +71 -0
  150. package/src/commands/add-ssh-key.ts +30 -0
  151. package/src/commands/buy.ts +83 -0
  152. package/src/commands/clone.ts +363 -0
  153. package/src/commands/index.ts +19 -0
  154. package/src/commands/info.ts +40 -0
  155. package/src/commands/login.ts +24 -0
  156. package/src/commands/logout.ts +27 -0
  157. package/src/commands/remove-ssh-key.ts +42 -0
  158. package/src/commands/subscribe.ts +84 -0
  159. package/src/commands/unsubscribe.ts +67 -0
  160. package/src/commands/utilities/asyncExec.ts +7 -0
  161. package/src/commands/utilities/branchExists.ts +15 -0
  162. package/src/commands/utilities/checkoutSelectionBranch.ts +62 -0
  163. package/src/commands/utilities/cherryPick.ts +23 -0
  164. package/src/commands/utilities/cloneRepo.ts +10 -0
  165. package/src/commands/utilities/convertNpmToYarn.ts +71 -0
  166. package/src/commands/utilities/convertTypeDocToJSDoc.ts +55 -0
  167. package/src/commands/utilities/convertTypeScriptToJavaScript.ts +526 -0
  168. package/src/commands/utilities/enableMergeDrivers.ts +55 -0
  169. package/src/commands/utilities/getCurrentBranch.ts +14 -0
  170. package/src/commands/utilities/getRepoRootPathSync.ts +13 -0
  171. package/src/commands/utilities/index.ts +17 -0
  172. package/src/commands/version.ts +22 -0
  173. package/src/commands/x-merge-json.ts +41 -0
  174. package/src/environment.ts +88 -0
  175. package/src/index.ts +30 -0
  176. package/src/logger.ts +29 -0
  177. package/src/pkg.ts +11 -0
  178. package/src/repoConfig.ts +6 -0
  179. package/src/types/global.ts +26 -0
  180. package/src/types/index.ts +53 -0
  181. package/src/types/process.env.d.ts +56 -0
  182. package/src/userConfig.ts +6 -0
  183. package/src/utilities/__tests__/getErrorMessage.ts +32 -0
  184. package/src/utilities/__tests__/timeAgo.ts +46 -0
  185. package/src/utilities/checkVersion.ts +31 -0
  186. package/src/utilities/getErrorMessage.ts +30 -0
  187. package/src/utilities/index.ts +14 -0
  188. package/src/utilities/readRepoConfig.ts +22 -0
  189. package/src/utilities/readUserConfig.ts +24 -0
  190. package/src/utilities/synchronizeUserConfig.ts +26 -0
  191. package/src/utilities/timeAgo.ts +39 -0
  192. package/src/utilities/userLoggedIn.ts +28 -0
  193. package/src/utilities/writeRepoConfig.ts +11 -0
  194. package/src/utilities/writeUserConfig.ts +13 -0
  195. package/tsconfig.json +25 -0
@@ -0,0 +1,526 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import ts from 'typescript'
4
+ import prettier from 'prettier'
5
+
6
+ /**
7
+ * Returns the name of some node.
8
+ */
9
+ const getName = (source, node) => {
10
+ const name = (node.name && node.name.escapedText)
11
+ || (node.parameters && source.substring(node.parameters.pos, node.parameters.end))
12
+
13
+ // Change type [key: string] to {...} so it will be parsed by JSDoc.
14
+ if (name === 'key: string') {
15
+ return '{...}'
16
+ }
17
+
18
+ return name
19
+ }
20
+
21
+ /**
22
+ * Returns the name of some type.
23
+ */
24
+ const getTypeName = (source, type) => {
25
+ let typeName = ``
26
+
27
+ if (!type) {
28
+ return `any`
29
+ }
30
+
31
+ if (type.typeName && type.typeName.escapedText) {
32
+ typeName = type.typeName.escapedText
33
+
34
+ if (type.typeArguments && type.typeArguments.length) {
35
+ const args = type.typeArguments.map(subType => getTypeName(source, subType)).join(', ')
36
+ typeName = `${typeName}<${args}>`
37
+ }
38
+ } else if (ts.isFunctionTypeNode(type) || ts.isFunctionLike(type)) {
39
+ typeName = 'function'
40
+ } else if (ts.isArrayTypeNode(type)) {
41
+ typeName = 'Array'
42
+ } else if (type.types) {
43
+ typeName = type.types.map(subType => getTypeName(source, subType)).join(' | ')
44
+ } else if (type.members && type.members.length) {
45
+ typeName = 'object'
46
+ } else {
47
+ typeName = source.substring(type.pos, type.end).trim()
48
+ }
49
+
50
+ typeName = typeName.replace(/`/g, `'`)
51
+ typeName = typeName.replace(`['`, `#`).replace(`']`, ``)
52
+ typeName = typeName.replace(/keyof .+/g, `string`)
53
+ typeName = typeName.replace(/<.+>/gi, ``)
54
+ typeName = typeName.replace(/typeof /gi, ``)
55
+
56
+ return typeName
57
+ }
58
+
59
+ /**
60
+ * Returns the JSDoc `@param` tag for some parameter.
61
+ */
62
+ const getJSDocParamTag = (source, parameter) => {
63
+ let parameterName = getName(source, parameter)
64
+ const parameterComment = (parameter.jsDoc && parameter.jsDoc[0] && parameter.jsDoc[0].comment) || ''
65
+
66
+ if (parameter.questionToken) {
67
+ parameterName = ['[', parameterName, ']'].join('')
68
+ }
69
+
70
+ return `@param {${getTypeName(source, parameter.type)}} ${parameterName}${parameterComment ? ` ${parameterComment}` : ``}`
71
+ }
72
+
73
+ /**
74
+ * Returns JSDoc `@property` tags for some type.
75
+ */
76
+ const getJSDocPropertyTags = (source, type, tags: string[] = [], parentName = '') => {
77
+ // Type could be an array of types like: `{sth: 1} | string` so parse each type separately.
78
+ const typesToCheck = [type]
79
+
80
+ if (type.types && type.types.length) {
81
+ typesToCheck.push(...type.types)
82
+ }
83
+
84
+ typesToCheck.forEach(type => {
85
+ // Handling array defined like this: {element1: 'something'}[]
86
+ if (ts.isArrayTypeNode(type) && type.elementType) {
87
+ getJSDocPropertyTags(source, type.elementType, tags, parentName ? parentName + '[]' : '[]')
88
+ }
89
+
90
+ // Handling Array<{element1: 'somethin'}>
91
+ if (type.typeName && type.typeName.escapedText === 'Array') {
92
+ if (type.typeArguments && type.typeArguments.length) {
93
+ type.typeArguments.forEach(subType => {
94
+ getJSDocPropertyTags(source, subType, tags, parentName ? parentName + '[]' : '')
95
+ })
96
+ }
97
+ }
98
+
99
+ // Handling {property1: "value"}
100
+ (type.members || []).filter(m => ts.isTypeElement(m)).forEach(member => {
101
+ let memberName = getName(source, member)
102
+ const memberComment = (member.jsDoc && member.jsDoc[0] && member.jsDoc[0].comment) || ''
103
+ const members = member.type.members || []
104
+ const memberTypeName = members.length ? 'object' : getTypeName(source, member.type)
105
+
106
+ if (parentName) {
107
+ memberName = [parentName, memberName].join('.')
108
+ }
109
+
110
+ tags.push(`@property {${memberTypeName}} ${member.questionToken ? `[${memberName}]` : memberName}${memberComment ? ` ${memberComment}` : ``}`)
111
+ getJSDocPropertyTags(source, member.type, tags, memberName)
112
+ })
113
+ })
114
+
115
+ return tags
116
+ }
117
+
118
+ /**
119
+ * Returns JSDoc comment lines and a method to append comment lines.
120
+ */
121
+ const useCommentLines = (source, jsDocNode) => {
122
+ const commentLines = jsDocNode
123
+ ? source.substring(jsDocNode.pos, jsDocNode.end).split(/(\n|\r|\r\n)/).filter(line => line.trim().length > 0)
124
+ : [`/**`, ` */`]
125
+
126
+ let appendedAtLeastOnce = jsDocNode ? false : true
127
+ const shouldUpdate = { current: false }
128
+
129
+ const appendComment = line => {
130
+ let args: (number | string)[] = [commentLines.length - 1, 0]
131
+
132
+ if (!appendedAtLeastOnce) {
133
+ appendedAtLeastOnce = true
134
+ args = args.concat(` *`)
135
+ }
136
+
137
+ args = args.concat([].concat(line).map(line => ` * ${line}`))
138
+ // eslint-disable-next-line prefer-spread
139
+ commentLines.splice.apply(commentLines, args)
140
+ shouldUpdate.current = true
141
+ }
142
+
143
+ return [ commentLines, appendComment, shouldUpdate ]
144
+ }
145
+
146
+ /**
147
+ * Updates JSDoc comments based on the type definitions.
148
+ */
149
+ const updateJSDocComments = (source, filename, modulePath) => {
150
+ const sourceFile = ts.createSourceFile(
151
+ filename,
152
+ source,
153
+ ts.ScriptTarget.Latest,
154
+ true
155
+ )
156
+
157
+ let updatedSource = source
158
+ let tempConstantIndex = 1
159
+
160
+ const isTest = modulePath.includes(`/__tests__/`) && !/\.(spec|test)\.tsx?$/.test(filename)
161
+
162
+ if (modulePath && !isTest) {
163
+ if (!updatedSource.includes(`* @module`)) {
164
+ updatedSource = `${updatedSource}\n\n/** @module ${modulePath} */`
165
+ }
166
+ }
167
+
168
+ for (const _statement of sourceFile.statements) {
169
+ const statement = _statement as ts.Statement & { jsDoc: ts.JSDocComment; declarationList: ts.VariableDeclarationList } // TODO fix this
170
+ const name = getName(source, statement)
171
+ const [ commentLines, appendComment, shouldUpdate ] = useCommentLines(source, statement.jsDoc && statement.jsDoc[0])
172
+
173
+ const appendMemberOf = () => {
174
+ if (modulePath && !isTest) {
175
+ appendComment([
176
+ `@memberof module:${modulePath}`,
177
+ ``
178
+ ])
179
+ }
180
+ }
181
+
182
+ let addCommentAfter = false
183
+
184
+ const declaration = statement.declarationList
185
+ && statement.declarationList.declarations
186
+ && statement.declarationList.declarations[0]
187
+
188
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
189
+ const initializer = declaration && declaration.initializer as ts.VariableDeclaration['initializer'] & { parameters: any } // TODO
190
+ const functionParameters = initializer && initializer.parameters
191
+
192
+ if (ts.isTypeAliasDeclaration(statement)) {
193
+ addCommentAfter = true
194
+
195
+ if (ts.isFunctionTypeNode(statement.type)) {
196
+ appendMemberOf()
197
+ appendComment(`@typedef {function} ${name}`)
198
+
199
+ statement.type.parameters.forEach(parameter => {
200
+ appendComment(getJSDocParamTag(source, parameter))
201
+ })
202
+ }
203
+
204
+ if (ts.isTypeLiteralNode(statement.type)) {
205
+ appendMemberOf()
206
+ appendComment(`@typedef {object} ${name}`)
207
+ getJSDocPropertyTags(source, statement.type).forEach(appendComment)
208
+ }
209
+
210
+ if (ts.isIntersectionTypeNode(statement.type)) {
211
+ appendMemberOf()
212
+ appendComment(`@typedef {object} ${name}`)
213
+ getJSDocPropertyTags(source, statement.type).forEach(appendComment)
214
+ }
215
+ } else if (ts.isInterfaceDeclaration(statement)) {
216
+ addCommentAfter = true
217
+
218
+ appendMemberOf()
219
+ appendComment(`@typedef ${name}`)
220
+
221
+ statement.members.forEach(member => {
222
+ const memberName = getName(source, member)
223
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
224
+ const memberType = (member as any).type // TODO
225
+ appendComment(`@property {${getTypeName(source, memberType)}} ${member.questionToken ? `[${memberName}]` : memberName}`)
226
+ })
227
+ } else if (ts.isClassDeclaration(statement)) {
228
+ const className = getName(source, statement)
229
+ const memberComments: string[] = []
230
+
231
+ statement.members.forEach(member => {
232
+ if (!ts.isPropertyDeclaration(member)) {
233
+ return
234
+ }
235
+
236
+ const modifiers = (member.modifiers || []).map(m => m.getText({text: source}))
237
+
238
+ modifiers.forEach(m => {
239
+ if (['private', 'public', 'protected'].includes(m)) {
240
+ memberComments.push(`@${m}`)
241
+ }
242
+ })
243
+
244
+ if (member.type) {
245
+ memberComments.push(`@type {${getTypeName(source, member.type)}}`)
246
+ }
247
+
248
+ if (modifiers.find((m => m === 'static'))) {
249
+ memberComments.push(`${className}.${getName(source, member)}`)
250
+ } else {
251
+ memberComments.push(`${className}.prototype.${getName(source, member)}`)
252
+ }
253
+
254
+ memberComments.forEach(appendComment)
255
+ })
256
+ } else if (declaration && declaration.type) {
257
+ appendMemberOf()
258
+ appendComment(`@type {${getTypeName(source, declaration.type)}}`)
259
+ } else if (functionParameters) {
260
+ appendMemberOf()
261
+ functionParameters.forEach(parameter => {
262
+ appendComment(getJSDocParamTag(source, parameter))
263
+ })
264
+ }
265
+
266
+ if (shouldUpdate.current) {
267
+ const newCommentBlock = commentLines.join(`\n`) // TODO .replace(/```ts/g, '```js')
268
+ const text = statement.getText().trim()
269
+ const fullText = statement.getFullText().trim()
270
+
271
+ if (filename.split(/\/|\\/).pop() === `types.ts` || !fullText || updatedSource.indexOf(fullText) < 0) {
272
+ updatedSource = `${updatedSource}\n\n${newCommentBlock}`
273
+ } else if (addCommentAfter) {
274
+ updatedSource = updatedSource.replace(statement.jsDoc ? fullText : text, `${text}\n\n${newCommentBlock}\nconst ___temp${tempConstantIndex++} = null`)
275
+ } else {
276
+ updatedSource = updatedSource.replace(statement.jsDoc ? fullText : text, `${newCommentBlock}\n${text}`)
277
+ }
278
+ }
279
+ }
280
+
281
+ return updatedSource
282
+ }
283
+
284
+ /**
285
+ * Recursively walks through the directories and converts all .ts and .tsx files
286
+ * to .js and .jsx files with JSDoc type annotations based on the type definitions.
287
+ *
288
+ * All other files are copied as is.
289
+ */
290
+ const transpileRecursively = (tsPath: string, jsPath: string, modulePath = '') => {
291
+ const files = fs.readdirSync(tsPath)
292
+
293
+ for (const file of files) {
294
+ const tsFile = path.join(tsPath, file)
295
+ const jsFile = path.join(jsPath, file.replace(/\.ts$/, '.js').replace(/\.tsx$/, '.jsx'))
296
+ const stats = fs.statSync(tsFile)
297
+
298
+ if (stats.isDirectory()) {
299
+ transpileRecursively(tsFile, jsFile, modulePath ? `${modulePath}/${file}` : file)
300
+ continue
301
+ } else if (!/\.tsx?$/.test(file)) {
302
+ // Ensure the directory exists.
303
+ if (!fs.existsSync(jsPath)) {
304
+ fs.mkdirSync(jsPath, { recursive: true })
305
+ }
306
+
307
+ fs.copyFileSync(tsFile, jsFile)
308
+ continue
309
+ } else if (/\.d\.ts$/.test(file)) {
310
+ continue
311
+ }
312
+
313
+ let source = fs.readFileSync(tsFile, 'utf8')
314
+
315
+ if (source.includes(`/** @ts-only */`)) {
316
+ // Skip copying of files with this flag.
317
+ continue
318
+ }
319
+
320
+ // Remove lines (usually type imports) containing the `// @ts-only` comment.
321
+ source = source.replace(/^(.*)\/\/ @ts-only(.*)(\r|\n|\r\n)/gm, ``)
322
+
323
+ // Preserve double dollar signs. No idea why these are being reduced to a single one.
324
+ source = source.replace(/\$\$\{/g, '__DOLLAR_SIGN__${')
325
+
326
+ // Ensure every module is covered.
327
+ source = source + `\n\n\nconst ___temp = null`
328
+
329
+ // Add the necessary JSDoc comments based on the type definitions.
330
+ source = updateJSDocComments(source, tsFile, modulePath ? `${modulePath}/${file.replace(/\.tsx?$/, ``)}` : file.replace(/\.tsx?$/, ``))
331
+
332
+ // Preserve line spacing.
333
+ source = source.replace(/(\n\n|\r\r|\r\n\r\n)/g, '\n/* __NEWLINE__ */')
334
+
335
+ // Get transpiled ESM code.
336
+ source = ts.transpileModule(source, {
337
+ compilerOptions: {
338
+ target: ts.ScriptTarget.ESNext,
339
+ module: ts.ModuleKind.ESNext,
340
+ moduleResolution: ts.ModuleResolutionKind.NodeJs,
341
+ esModuleInterop: true,
342
+ strict: false,
343
+ jsx: /\.tsx$/.test(file) ? ts.JsxEmit.Preserve : ts.JsxEmit.None,
344
+ newLine: ts.NewLineKind.LineFeed,
345
+ removeComments: false,
346
+ pretty: true
347
+ }
348
+ }).outputText
349
+
350
+ // Restore line spacing.
351
+ source = source.replace(/\/\* __NEWLINE__ \*\//g, '\n')
352
+
353
+ // Remove the temporary constants.
354
+ source = source.replace(/const ___temp(|[0-9]+) = null/g, '')
355
+
356
+ // Remove @typescript-eslint lines.
357
+ source = source.replace(/(\s|)(\/\/|\/\*) eslint-disable(|-next-line) @typescript-eslint\/.*?(\n|\r|\r\n)/gi, `\n`)
358
+
359
+ try {
360
+ // Make the code pretty again.
361
+ source = prettier.format(source, {
362
+ filepath: jsFile,
363
+ printWidth: 120,
364
+ semi: false,
365
+ singleQuote: true,
366
+ quoteProps: 'consistent',
367
+ jsxSingleQuote: true,
368
+ trailingComma: 'none'
369
+ })
370
+ } catch (error) {
371
+ console.error(error)
372
+ console.log(tsFile)
373
+ console.log(source)
374
+ }
375
+
376
+ // Restore double dollar signs.
377
+ source = source.replace(/__DOLLAR_SIGN__/g, '$')
378
+
379
+ if (source.trim().length && source.trim() !== `export {}`) {
380
+ // Ensure the directory exists.
381
+ if (!fs.existsSync(jsPath)) {
382
+ fs.mkdirSync(jsPath, { recursive: true })
383
+ }
384
+
385
+ // Write the JavaScript file.
386
+ fs.writeFileSync(jsFile, source)
387
+ }
388
+ }
389
+ }
390
+
391
+ /**
392
+ * A very quick and dirty hacked together script to convert a TypeScript codebase to JavaScript one.
393
+ */
394
+ export const convertTypeScriptToJavaScript = async (cwd = `.`) => {
395
+ const tsPath = path.join(cwd, `src-ts`)
396
+ const jsPath = path.join(cwd, `src`)
397
+
398
+ try {
399
+ // Transpile all TypeScript to JavaScript.
400
+ fs.renameSync(jsPath, tsPath)
401
+ fs.mkdirSync(jsPath)
402
+ transpileRecursively(tsPath, jsPath)
403
+ fs.rmSync(tsPath, { recursive: true, force: true })
404
+ } catch (error) {
405
+ }
406
+
407
+ try {
408
+ // Remove TypeScript dependencies and replace `.ts` with `.js` in `package.json`.
409
+ const packageJsonPath = path.join(cwd, `package.json`)
410
+ const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, `utf8`))
411
+
412
+ delete packageJson.devDependencies[`ts-node`]
413
+ delete packageJson.devDependencies[`typescript`]
414
+ delete packageJson.devDependencies[`@babel/preset-typescript`]
415
+
416
+ for (const moduleName in packageJson.devDependencies) {
417
+ if (/^@(types\/|typescript(\/|-))/.test(moduleName)) {
418
+ delete packageJson.devDependencies[moduleName]
419
+ }
420
+ }
421
+
422
+ for (const scriptName in packageJson.scripts) {
423
+ const script = packageJson.scripts[scriptName]
424
+
425
+ if (script.includes(` --loader=ts-node/esm`)) {
426
+ packageJson.scripts[scriptName] = script
427
+ .replace(/ --loader=ts-node\/esm/g, ``)
428
+ .replace(/\.tsx\b/g, `.jsx`)
429
+ .replace(/\.ts\b/g, `.js`)
430
+ }
431
+ }
432
+
433
+ if (packageJson.scripts.build === `tsc`) {
434
+ delete packageJson.scripts.build
435
+ }
436
+
437
+ if (packageJson.scripts.start) {
438
+ packageJson.scripts.start = packageJson.scripts.start.replace(`node build/`, `node src/`)
439
+ }
440
+
441
+ await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2))
442
+ } catch (error) {
443
+ }
444
+
445
+ try {
446
+ // Remove `tsconfig.json`.
447
+ await fs.promises.rm(path.join(cwd, `tsconfig.json`))
448
+ } catch (error) {
449
+ }
450
+
451
+ try {
452
+ // Update `.eslintrc.json`.
453
+ const eslintConfigPath = path.join(cwd, `.eslintrc.json`)
454
+ const eslintConfig = JSON.parse(await fs.promises.readFile(eslintConfigPath, `utf8`))
455
+
456
+ if (eslintConfig.plugins) {
457
+ eslintConfig.plugins = eslintConfig.plugins.filter(plugin => plugin !== `@typescript-eslint`)
458
+ }
459
+
460
+ delete eslintConfig.parser
461
+
462
+ if (eslintConfig.extends) {
463
+ eslintConfig.extends = eslintConfig.extends.filter(extend => extend !== `plugin:@typescript-eslint/recommended`)
464
+ }
465
+
466
+ if (eslintConfig.rules) {
467
+ for (const key in eslintConfig.rules) {
468
+ if (/^@typescript-/.test(key)) {
469
+ delete eslintConfig.rules[key]
470
+ }
471
+ }
472
+ }
473
+
474
+ await fs.promises.writeFile(eslintConfigPath, JSON.stringify(eslintConfig, null, 2))
475
+ } catch (error) {
476
+ }
477
+
478
+ try {
479
+ // Update `jest.config.json` if it exists.
480
+ const jestConfigPath = path.join(cwd, `jest.config.json`)
481
+ await fs.promises.access(jestConfigPath, fs.constants.R_OK | fs.constants.R_OK)
482
+ await fs.promises.writeFile(jestConfigPath, JSON.stringify({
483
+ "roots": [
484
+ "<rootDir>/src/"
485
+ ],
486
+ "setupFiles": [
487
+ "<rootDir>/src/environment.js"
488
+ ],
489
+ "moduleNameMapper": {
490
+ "^(\\.{1,2}/.*)\\.jsx?$": "$1"
491
+ }
492
+ }, null, 2))
493
+ } catch (error) {
494
+ }
495
+
496
+ try {
497
+ // Update `babel.config.json` if it exists.
498
+ const babelConfigPath = path.join(cwd, `babel.config.json`)
499
+ const babelConfig = JSON.parse(await fs.promises.readFile(babelConfigPath, `utf8`))
500
+ babelConfig.presets = babelConfig.presets.filter(preset => preset !== `@babel/preset-typescript`)
501
+ await fs.promises.writeFile(babelConfigPath, JSON.stringify(babelConfig, null, 2))
502
+ } catch (error) {
503
+ }
504
+
505
+ try {
506
+ // Replace all TypeScript info with JavaScript.
507
+ const readmePath = path.join(cwd, `README.md`)
508
+ let README = await fs.promises.readFile(readmePath, `utf8`)
509
+
510
+ README = README
511
+ .replace(`\r\n- [\`ts-node\`](https://www.npmjs.com/package/ts-node) - Allows us to run TypeScript (.ts) files as easily as JavaScript (.js) files.\r\n`, ``)
512
+ .replace(`Uses the [TypeScript](typescriptlang.org) compiler to compile the \`*.ts\` files within the \`src\` directory into \`*.js\` files within the \`build\` directory. You probably don't need to use this unless you're explicitly running the production build locally, as [\`ts-node\`](https://www.npmjs.com/package/ts-node) handles everything for you in development.`, ``)
513
+ .replace(`### \`npm run build\`\r\n\r\n\r\n\r\n\r\n`, ``)
514
+ .replace(`### \`yarn run build\`\r\n\r\n\r\n\r\n\r\n`, ``)
515
+ .replace(`\r\n- \`@types/*\` - Type definitions for popular libraries. See [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) for more information.\r\n`, ``)
516
+ .replace(`\r\n- \`@typescript-eslint/*\` - Enables linting of our TypeScript codebase.\r\n`, ``)
517
+ .replace(`\r\n- [\`typescript\`](https://www.npmjs.com/package/typescript) - Necessary for TypeScript support.\r\n`, ``)
518
+ .replace(/www\.typescriptlang\.org/g, `developer.mozilla.org/en-US/docs/Web/JavaScript`)
519
+ .replace(/JavaScript and TypeScript/g, `JavaScript`)
520
+ .replace(/TypeScript/g, `JavaScript`)
521
+ .replace(/\.ts\b/g, `.js`)
522
+
523
+ await fs.promises.writeFile(readmePath, README)
524
+ } catch (error) {
525
+ }
526
+ }
@@ -0,0 +1,55 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import { logger } from '../../logger.js'
4
+
5
+ /**
6
+ * A bit of a hack to make it easier to merge many different commits across various branches.
7
+ *
8
+ * Creates or updates the .gitattributes file to use custom merge strategies for every file.
9
+ *
10
+ * Uses a custom JSON merge driver for `.json` files, and diff3 + union for all others.
11
+ */
12
+ export const enableMergeDrivers = (repoPath = ``) => {
13
+ const gitConfigPath = repoPath ? path.join(repoPath, `.git`, `config`) : path.join(`.git`, `config`)
14
+ const gitConfigExisted = fs.existsSync(gitConfigPath)
15
+ const originalGitConfig = (gitConfigExisted && fs.readFileSync(gitConfigPath, `utf8`)) || ``
16
+ const gitAttributesPath = repoPath ? path.join(repoPath, `.gitattributes`) : path.join(`.gitattributes`)
17
+ const gitAttributesExisted = fs.existsSync(gitAttributesPath)
18
+ const originalGitAttributes = (gitAttributesExisted && fs.readFileSync(gitAttributesPath, `utf8`)) || ``
19
+
20
+ logger.info(`Enabling custom merge drivers...`)
21
+
22
+ fs.appendFileSync(gitConfigPath, [
23
+ ``,
24
+ `[merge "json"]`,
25
+ ` name = custom merge driver for json files`,
26
+ ` driver = npx mlcl x-merge-json %O %A %B`,
27
+ `[merge "diff3-union"]`,
28
+ ` name = custom merge driver for all other files`,
29
+ ` driver = git merge-file --diff3 --union %A %O %B`,
30
+ ``,
31
+ ].join(`\n`))
32
+
33
+ fs.appendFileSync(gitAttributesPath, [
34
+ ``,
35
+ `* merge=diff3-union`,
36
+ `*.json merge=json`,
37
+ ``,
38
+ ].join(`\n`))
39
+
40
+ return () => {
41
+ logger.info(`Removing custom merge drivers...`)
42
+
43
+ if (gitConfigExisted) {
44
+ fs.writeFileSync(gitConfigPath, originalGitConfig)
45
+ } else {
46
+ fs.unlinkSync(gitConfigPath)
47
+ }
48
+
49
+ if (gitAttributesExisted) {
50
+ fs.writeFileSync(gitAttributesPath, originalGitAttributes)
51
+ } else {
52
+ fs.unlinkSync(gitAttributesPath)
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,14 @@
1
+ import { asyncExec } from './asyncExec.js'
2
+
3
+ /**
4
+ * Returns the name of the current branch.
5
+ */
6
+ export const getCurrentBranch = async (repoPath = ``) => {
7
+ const { stdout, stderr } = await asyncExec(`git${repoPath ? ` -C "${repoPath}"` : ``} branch --show-current`)
8
+
9
+ if (stderr) {
10
+ throw new Error(stderr)
11
+ }
12
+
13
+ return stdout.replace(/^\* /, ``).trim()
14
+ }
@@ -0,0 +1,13 @@
1
+ import { spawnSync } from 'child_process'
2
+
3
+ /**
4
+ * Returns the root path of the current git repository.
5
+ */
6
+ export const getRepoRootPathSync = () => {
7
+ try {
8
+ const spawn = spawnSync('git', ['rev-parse', '--show-toplevel'])
9
+ return spawn.stdout.toString().trim() || `.`
10
+ } catch (error) {
11
+ return `.`
12
+ }
13
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Utilities for common commands.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ export * from './asyncExec.js'
8
+ export * from './branchExists.js'
9
+ export * from './checkoutSelectionBranch.js'
10
+ export * from './cherryPick.js'
11
+ export * from './cloneRepo.js'
12
+ export * from './convertNpmToYarn.js'
13
+ export * from './convertTypeDocToJSDoc.js'
14
+ export * from './convertTypeScriptToJavaScript.js'
15
+ export * from './enableMergeDrivers.js'
16
+ export * from './getCurrentBranch.js'
17
+ export * from './getRepoRootPathSync.js'
@@ -0,0 +1,22 @@
1
+ import fs from 'fs'
2
+ import { fileURLToPath } from 'url'
3
+ import path from 'path'
4
+ import { Command } from 'commander'
5
+
6
+ const __dirname = fileURLToPath(path.dirname(import.meta.url))
7
+
8
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, `../../package.json`), `utf8`)) as {
9
+ name: string
10
+ description: string
11
+ version: string
12
+ }
13
+
14
+ /**
15
+ * Adds the `version` command to the program.
16
+ */
17
+ export const version = (program: Command) => {
18
+ program
19
+ .name(process.env.APP_NAME || pkg.name)
20
+ .description(pkg.description)
21
+ .version(process.env.APP_VERSION || pkg.version)
22
+ }
@@ -0,0 +1,41 @@
1
+ import { Command } from 'commander'
2
+ import fs from 'fs'
3
+ import xdiff from 'xdiff'
4
+ import detectIndent from 'detect-indent'
5
+
6
+ const encoding = 'utf8'
7
+
8
+ /**
9
+ * Adds the `x-merge-json` command to the program.
10
+ *
11
+ * Based off of https://github.com/jonatanpedersen/git-json-merge.
12
+ * Using our own implementation here because we're going to improve it later.
13
+ */
14
+ export const xMergeJSON = (program: Command) => {
15
+ program.command(`x-merge-json`)
16
+ .description(`git merge driver for JSON files`)
17
+ .argument(`[baseFilename]`, `base filename`)
18
+ .argument(`[oursFilename]`, `ours filename`)
19
+ .argument(`[theirsFilename]`, `theirs filename`)
20
+ .action(async (baseFilename, oursFilename, theirsFilename) => {
21
+ const baseJson = fs.readFileSync(baseFilename, encoding)
22
+ const base = JSON.parse(baseJson)
23
+ const baseIndent = detectIndent(baseJson).indent
24
+
25
+ const oursJson = fs.readFileSync(oursFilename, encoding)
26
+ const ours = JSON.parse(oursJson)
27
+ const oursIndent = detectIndent(oursJson).indent
28
+
29
+ const theirsJson = fs.readFileSync(theirsFilename, encoding)
30
+ const theirs = JSON.parse(theirsJson)
31
+ const theirsIndent = detectIndent(theirsJson).indent
32
+
33
+ const indent = oursIndent !== baseIndent ? oursIndent : theirsIndent !== baseIndent ? theirsIndent : baseIndent
34
+
35
+ const diff = xdiff.diff3(ours, base, theirs)
36
+ const newOurs = diff ? xdiff.patch(base, diff) : base
37
+ const newOursJson = JSON.stringify(newOurs, null, indent)
38
+
39
+ fs.writeFileSync(oursFilename, newOursJson, encoding)
40
+ })
41
+ }