@neurodevs/meta-node 0.1.0 → 0.2.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 (29) hide show
  1. package/.vscode/tasks.json +18 -0
  2. package/build/__tests__/modules/NpmAutopackage.test.d.ts +47 -12
  3. package/build/__tests__/modules/NpmAutopackage.test.js +314 -34
  4. package/build/__tests__/modules/NpmAutopackage.test.js.map +1 -1
  5. package/build/index.d.ts +6 -2
  6. package/build/index.js +11 -5
  7. package/build/index.js.map +1 -1
  8. package/build/modules/NpmAutopackage.d.ts +49 -16
  9. package/build/modules/NpmAutopackage.js +221 -41
  10. package/build/modules/NpmAutopackage.js.map +1 -1
  11. package/build/scripts/runAutopackage.js +4 -2
  12. package/build/scripts/runAutopackage.js.map +1 -1
  13. package/build/testDoubles/Autopackage/FakeAutopackage.d.ts +8 -0
  14. package/build/testDoubles/Autopackage/FakeAutopackage.js +18 -0
  15. package/build/testDoubles/Autopackage/FakeAutopackage.js.map +1 -0
  16. package/package.json +5 -1
  17. package/src/__tests__/modules/NpmAutopackage.test.ts +415 -33
  18. package/src/index.ts +9 -3
  19. package/src/modules/NpmAutopackage.ts +272 -42
  20. package/src/scripts/runAutopackage.ts +4 -2
  21. package/src/testDoubles/Autopackage/FakeAutopackage.ts +19 -0
  22. package/build/__tests__/modules/PackageJsonUpdater.test.d.ts +0 -7
  23. package/build/__tests__/modules/PackageJsonUpdater.test.js +0 -63
  24. package/build/__tests__/modules/PackageJsonUpdater.test.js.map +0 -1
  25. package/build/modules/PackageJsonUpdater.d.ts +0 -8
  26. package/build/modules/PackageJsonUpdater.js +0 -10
  27. package/build/modules/PackageJsonUpdater.js.map +0 -1
  28. package/src/__tests__/modules/PackageJsonUpdater.test.ts +0 -23
  29. package/src/modules/PackageJsonUpdater.ts +0 -13
@@ -1,22 +1,41 @@
1
1
  import { execSync } from 'child_process'
2
+ import fs from 'fs'
2
3
 
3
4
  export default class NpmAutopackage implements Autopackage {
4
5
  public static Class?: AutopackageConstructor
5
6
  public static chdir = process.chdir
6
7
  public static execSync = execSync
8
+ public static existsSync = fs.existsSync
9
+ public static fetch = globalThis.fetch
10
+ public static readFileSync = fs.readFileSync
11
+ public static writeFileSync = fs.writeFileSync
7
12
 
8
13
  private packageName: string
9
14
  private packageDescription: string
10
15
  private gitNamespace: string
11
16
  private installDir: string
17
+ private keywords?: string[]
18
+ private license?: string
19
+ private author?: string
12
20
 
13
21
  protected constructor(options: AutopackageOptions) {
14
- const { name, description, gitNamespace, installDir } = options
22
+ const {
23
+ name,
24
+ description,
25
+ gitNamespace,
26
+ installDir,
27
+ license,
28
+ author,
29
+ keywords,
30
+ } = options
15
31
 
16
32
  this.packageName = name
17
33
  this.packageDescription = description
18
34
  this.gitNamespace = gitNamespace
19
35
  this.installDir = installDir
36
+ this.keywords = keywords
37
+ this.license = license
38
+ this.author = author
20
39
  }
21
40
 
22
41
  public static async Create(options: AutopackageOptions) {
@@ -27,62 +46,269 @@ export default class NpmAutopackage implements Autopackage {
27
46
  }
28
47
 
29
48
  public async createPackage() {
30
- this.execCreateModule()
31
- this.execGitSetup()
32
- this.execSetupVscode()
33
- }
49
+ this.throwIfGithubTokenNotInEnv()
50
+
51
+ await this.createRepoInGithubOrg()
34
52
 
35
- private execCreateModule() {
36
53
  this.chdirToInstallDir()
37
- this.exec(this.createModuleCmd)
54
+ this.cloneGitRepo()
55
+ this.chdirToPackageDir()
56
+ this.spruceCreateModule()
57
+ this.updatePackage()
58
+ this.updateGitignore()
59
+ this.setupVscode()
38
60
  }
39
61
 
40
- private execGitSetup() {
41
- this.chdirToNewPackageDir()
62
+ private throwIfGithubTokenNotInEnv() {
63
+ if (!this.githubToken) {
64
+ throw new Error('\n\nPlease set process.env.GITHUB_TOKEN!\n')
65
+ }
66
+ }
67
+
68
+ private get githubToken() {
69
+ return process.env.GITHUB_TOKEN
70
+ }
42
71
 
43
- this.gitInit()
44
- this.gitAdd()
45
- this.gitCommitCreateModule()
46
- this.gitRemoteAddOrigin()
72
+ private async createRepoInGithubOrg() {
73
+ await this.fetch(
74
+ `https://api.github.com/orgs/${this.gitNamespace}/repos`,
75
+ {
76
+ method: 'POST',
77
+ headers: {
78
+ Authorization: `token ${this.githubToken}`,
79
+ Accept: 'application/vnd.github+json',
80
+ 'Content-Type': 'application/json',
81
+ },
82
+ body: JSON.stringify({
83
+ name: this.packageName,
84
+ private: false,
85
+ description: this.packageDescription,
86
+ auto_init: true,
87
+ gitignore_template: 'Node',
88
+ license_template: 'mit',
89
+ }),
90
+ }
91
+ )
92
+ }
93
+
94
+ private chdirToInstallDir() {
95
+ this.chdir(this.installDir)
47
96
  }
48
97
 
49
- private gitInit() {
50
- this.exec(this.initCmd)
98
+ private cloneGitRepo() {
99
+ if (!this.packageDirExists) {
100
+ this.exec(`git clone ${this.gitUrl}`)
101
+ }
51
102
  }
52
103
 
53
- private gitAdd() {
54
- this.exec(this.addCmd)
104
+ private get packageDirExists() {
105
+ return this.existsSync(this.packageDir)
55
106
  }
56
107
 
57
- private gitCommitCreateModule() {
58
- this.exec(this.commitCreateCmd)
108
+ private get packageDir() {
109
+ return `${this.installDir}/${this.packageName}`
59
110
  }
60
111
 
61
- private gitRemoteAddOrigin() {
62
- this.exec(this.addRemoteCmd)
112
+ private get gitUrl() {
113
+ return `https://github.com/${this.gitNamespace}/${this.packageName}.git`
63
114
  }
64
115
 
65
- private execSetupVscode() {
66
- this.exec(this.setupVscodeCmd)
116
+ private chdirToPackageDir() {
117
+ this.chdir(this.packageDir)
118
+ }
67
119
 
68
- this.gitAdd()
69
- this.gitCommitSetupVscode()
120
+ private spruceCreateModule() {
121
+ if (!this.packageJsonExists) {
122
+ this.execSpruceCreateModule()
123
+ this.commitCreatePackage()
124
+ }
70
125
  }
71
126
 
72
- private gitCommitSetupVscode() {
73
- this.exec(this.commitVscodeCmd)
127
+ private get packageJsonExists() {
128
+ return this.existsSync(this.packageJsonPath)
74
129
  }
75
130
 
76
- private chdirToInstallDir() {
77
- this.chdir(this.installDir)
131
+ private get packageJsonPath() {
132
+ return `${this.packageDir}/package.json`
78
133
  }
79
134
 
80
- private chdirToNewPackageDir() {
81
- this.chdir(this.packageDir)
135
+ private execSpruceCreateModule() {
136
+ this.exec(
137
+ `spruce create.module --name "${this.packageName}" --destination "${this.installDir}/${this.packageName}" --description "${this.packageDescription}"`
138
+ )
82
139
  }
83
140
 
84
- private get packageDir() {
85
- return `${this.installDir}/${this.packageName}`
141
+ private commitCreatePackage() {
142
+ this.gitAddAll()
143
+ this.gitCommitCreatePackage()
144
+ this.gitPush()
145
+ }
146
+
147
+ private gitAddAll() {
148
+ this.exec('git add .')
149
+ }
150
+
151
+ private gitCommitCreatePackage() {
152
+ this.exec('git commit -m "patch: create package"')
153
+ }
154
+
155
+ private gitPush() {
156
+ this.exec('git push')
157
+ }
158
+
159
+ private updatePackage() {
160
+ if (!this.packageUpdated) {
161
+ this.updatePackageJson()
162
+ this.commitUpdatePackage()
163
+ }
164
+ }
165
+
166
+ private get packageUpdated() {
167
+ return this.pkg.name === `@${this.scopedPackage}`
168
+ }
169
+
170
+ private get pkg() {
171
+ const raw = this.readFileSync(this.packageJsonPath, {
172
+ encoding: 'utf-8',
173
+ })
174
+ return JSON.parse(raw)
175
+ }
176
+
177
+ private updatePackageJson() {
178
+ const updated = { ...this.pkg, ...this.updatedJsonFile }
179
+ const ordered = this.orderJsonKeys(updated, [
180
+ 'name',
181
+ 'version',
182
+ 'description',
183
+ 'keywords',
184
+ 'license',
185
+ 'author',
186
+ 'homepage',
187
+ 'repository',
188
+ 'bugs',
189
+ 'main',
190
+ 'scripts',
191
+ 'dependencies',
192
+ 'devDependencies',
193
+ 'jest',
194
+ 'skill',
195
+ ])
196
+
197
+ this.writeFileSync(
198
+ this.packageJsonPath,
199
+ JSON.stringify(ordered, null, 2) + '\n',
200
+ { encoding: 'utf-8' }
201
+ )
202
+ }
203
+
204
+ private get updatedJsonFile() {
205
+ return {
206
+ name: `@${this.scopedPackage}`,
207
+ keywords: this.keywords ?? [],
208
+ license: this.license,
209
+ author: this.author,
210
+ main: 'build/index.js',
211
+ homepage: `https://github.com/${this.gitNamespace}/${this.packageName}`,
212
+ repository: {
213
+ type: 'git',
214
+ url: `git+https://github.com/${this.gitNamespace}/${this.packageName}.git`,
215
+ },
216
+ bugs: {
217
+ url: `https://github.com/${this.gitNamespace}/${this.packageName}/issues`,
218
+ },
219
+ dependencies: {},
220
+ }
221
+ }
222
+
223
+ private get scopedPackage() {
224
+ return `${this.gitNamespace}/${this.packageName}`
225
+ }
226
+
227
+ private orderJsonKeys(json: Record<string, unknown>, keyOrder: string[]) {
228
+ const ordered: Record<string, any> = {}
229
+
230
+ for (const key of keyOrder) {
231
+ if (key in json) {
232
+ ordered[key] = json[key]
233
+ }
234
+ }
235
+
236
+ const remainingKeys = Object.keys(json)
237
+ .filter((k) => !keyOrder.includes(k))
238
+ .sort()
239
+
240
+ for (const key of remainingKeys) {
241
+ ordered[key] = json[key]
242
+ }
243
+
244
+ return ordered
245
+ }
246
+
247
+ private commitUpdatePackage() {
248
+ this.gitAddAll()
249
+ this.gitCommitUpdatePackage()
250
+ this.gitPush()
251
+ }
252
+
253
+ private gitCommitUpdatePackage() {
254
+ this.exec('git commit -m "patch: update package"')
255
+ }
256
+
257
+ private updateGitignore() {
258
+ if (!this.gitignoreUpdated) {
259
+ this.writeFileSync(this.gitignorePath, '\nbuild/\n', {
260
+ encoding: 'utf-8',
261
+ flag: 'a',
262
+ })
263
+ this.commitUpdateGitignore()
264
+ }
265
+ }
266
+
267
+ private get gitignoreUpdated() {
268
+ const content = this.readFileSync(this.gitignorePath, {
269
+ encoding: 'utf-8',
270
+ })
271
+ const lines = content.split(/\r?\n/).map((line) => line.trim())
272
+ return lines.includes('build/')
273
+ }
274
+
275
+ private get gitignorePath() {
276
+ return `${this.packageDir}/.gitignore`
277
+ }
278
+
279
+ private commitUpdateGitignore() {
280
+ this.gitAddAll()
281
+ this.gitCommitUpdateGitignore()
282
+ this.gitPush()
283
+ }
284
+
285
+ private gitCommitUpdateGitignore() {
286
+ this.exec('git commit -m "patch: add build dir to gitignore"')
287
+ }
288
+
289
+ private setupVscode() {
290
+ if (!this.vscodeSettingsExists) {
291
+ this.spruceSetupVscode()
292
+ this.commitSetupVscode()
293
+ }
294
+ }
295
+
296
+ private get vscodeSettingsExists() {
297
+ return this.existsSync(`${this.packageDir}/.vscode/settings.json`)
298
+ }
299
+
300
+ private spruceSetupVscode() {
301
+ this.exec('spruce setup.vscode --all true')
302
+ }
303
+
304
+ private commitSetupVscode() {
305
+ this.gitAddAll()
306
+ this.gitCommitSetup()
307
+ this.gitPush()
308
+ }
309
+
310
+ private gitCommitSetup() {
311
+ this.exec('git commit -m "patch: setup vscode"')
86
312
  }
87
313
 
88
314
  private get chdir() {
@@ -93,20 +319,21 @@ export default class NpmAutopackage implements Autopackage {
93
319
  return NpmAutopackage.execSync
94
320
  }
95
321
 
96
- private get createModuleCmd() {
97
- return `spruce create.module --name "${this.packageName}" --destination "${this.installDir}/${this.packageName}" --description "${this.packageDescription}"`
322
+ private get existsSync() {
323
+ return NpmAutopackage.existsSync
98
324
  }
99
325
 
100
- private readonly initCmd = 'git init'
101
- private readonly addCmd = 'git add .'
102
- private readonly commitCreateCmd = 'git commit -m "patch: create module"'
326
+ private get fetch() {
327
+ return NpmAutopackage.fetch
328
+ }
103
329
 
104
- private get addRemoteCmd() {
105
- return `git remote add origin "https://github.com/${this.gitNamespace}/${this.packageName}.git"`
330
+ private get readFileSync() {
331
+ return NpmAutopackage.readFileSync
106
332
  }
107
333
 
108
- private readonly setupVscodeCmd = 'spruce setup.vscode --all true'
109
- private readonly commitVscodeCmd = 'git commit -m "patch: setup vscode"'
334
+ private get writeFileSync() {
335
+ return NpmAutopackage.writeFileSync
336
+ }
110
337
  }
111
338
 
112
339
  export interface Autopackage {
@@ -119,6 +346,9 @@ export interface AutopackageOptions {
119
346
  gitNamespace: string
120
347
  npmNamespace: string
121
348
  installDir: string
349
+ keywords?: string[]
350
+ license?: string
351
+ author?: string
122
352
  }
123
353
 
124
354
  export type AutopackageConstructor = new () => Autopackage
@@ -5,11 +5,13 @@ async function main() {
5
5
  console.log('Running autopackage...')
6
6
 
7
7
  await NpmAutopackage.Create({
8
- name: 'node-xyz',
9
- description: 'XYZ, yo',
8
+ name: 'node-osf',
9
+ description: 'Node.js client for the Open Science Framework (OSF) API',
10
10
  gitNamespace: 'neurodevs',
11
11
  npmNamespace: 'neurodevs',
12
12
  installDir: '/Users/ericthecurious/dev',
13
+ license: 'MIT',
14
+ author: 'Eric Yates <hello@ericthecurious.com>',
13
15
  })
14
16
 
15
17
  console.log('Opening in VSCode...')
@@ -0,0 +1,19 @@
1
+ import { Autopackage, AutopackageOptions } from '../../modules/NpmAutopackage'
2
+
3
+ export default class FakeAutopackage implements Autopackage {
4
+ public static callsToConstructor: AutopackageOptions[] = []
5
+ public static numCallsToCreatePackage = 0
6
+
7
+ public constructor(options: AutopackageOptions) {
8
+ FakeAutopackage.callsToConstructor.push(options)
9
+ }
10
+
11
+ public async createPackage() {
12
+ FakeAutopackage.numCallsToCreatePackage++
13
+ }
14
+
15
+ public static resetTestDouble() {
16
+ this.callsToConstructor = []
17
+ this.numCallsToCreatePackage = 0
18
+ }
19
+ }
@@ -1,7 +0,0 @@
1
- import AbstractSpruceTest from '@sprucelabs/test-utils';
2
- export default class PackageJsonUpdaterTest extends AbstractSpruceTest {
3
- private static instance;
4
- protected static beforeEach(): Promise<void>;
5
- protected static createsInstance(): Promise<void>;
6
- private static PackageJsonUpdater;
7
- }
@@ -1,63 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
- return c > 3 && r && Object.defineProperty(target, key, r), r;
23
- };
24
- var __importStar = (this && this.__importStar) || (function () {
25
- var ownKeys = function(o) {
26
- ownKeys = Object.getOwnPropertyNames || function (o) {
27
- var ar = [];
28
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
- return ar;
30
- };
31
- return ownKeys(o);
32
- };
33
- return function (mod) {
34
- if (mod && mod.__esModule) return mod;
35
- var result = {};
36
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
- __setModuleDefault(result, mod);
38
- return result;
39
- };
40
- })();
41
- var __importDefault = (this && this.__importDefault) || function (mod) {
42
- return (mod && mod.__esModule) ? mod : { "default": mod };
43
- };
44
- Object.defineProperty(exports, "__esModule", { value: true });
45
- const test_utils_1 = __importStar(require("@sprucelabs/test-utils"));
46
- const PackageJsonUpdater_1 = __importDefault(require("../../modules/PackageJsonUpdater"));
47
- class PackageJsonUpdaterTest extends test_utils_1.default {
48
- static async beforeEach() {
49
- await super.beforeEach();
50
- this.instance = this.PackageJsonUpdater();
51
- }
52
- static async createsInstance() {
53
- test_utils_1.assert.isTruthy(this.instance, 'Failed to create instance!');
54
- }
55
- static PackageJsonUpdater() {
56
- return PackageJsonUpdater_1.default.Create();
57
- }
58
- }
59
- exports.default = PackageJsonUpdaterTest;
60
- __decorate([
61
- (0, test_utils_1.test)()
62
- ], PackageJsonUpdaterTest, "createsInstance", null);
63
- //# sourceMappingURL=PackageJsonUpdater.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PackageJsonUpdater.test.js","sourceRoot":"","sources":["../../../src/__tests__/modules/PackageJsonUpdater.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qEAAyE;AACzE,0FAEyC;AAEzC,MAAqB,sBAAuB,SAAQ,oBAAkB;IAGxD,MAAM,CAAC,KAAK,CAAC,UAAU;QAC7B,MAAM,KAAK,CAAC,UAAU,EAAE,CAAA;QAExB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAA;IAC7C,CAAC;IAGsB,AAAb,MAAM,CAAC,KAAK,CAAC,eAAe;QAClC,mBAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,4BAA4B,CAAC,CAAA;IAChE,CAAC;IAEO,MAAM,CAAC,kBAAkB;QAC7B,OAAO,4BAAkB,CAAC,MAAM,EAAE,CAAA;IACtC,CAAC;CACJ;AAjBD,yCAiBC;AAP0B;IADtB,IAAA,iBAAI,GAAE;mDAGN"}
@@ -1,8 +0,0 @@
1
- export default class PackageJsonUpdater implements JsonUpdater {
2
- static Class?: JsonUpdateConstructor;
3
- protected constructor();
4
- static Create(): PackageJsonUpdater;
5
- }
6
- export interface JsonUpdater {
7
- }
8
- export type JsonUpdateConstructor = new () => JsonUpdater;
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- class PackageJsonUpdater {
4
- constructor() { }
5
- static Create() {
6
- return new (this.Class ?? this)();
7
- }
8
- }
9
- exports.default = PackageJsonUpdater;
10
- //# sourceMappingURL=PackageJsonUpdater.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PackageJsonUpdater.js","sourceRoot":"","sources":["../../src/modules/PackageJsonUpdater.ts"],"names":[],"mappings":";;AAAA,MAAqB,kBAAkB;IAGnC,gBAAyB,CAAC;IAEnB,MAAM,CAAC,MAAM;QAChB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,CAAA;IACrC,CAAC;CACJ;AARD,qCAQC"}
@@ -1,23 +0,0 @@
1
- import AbstractSpruceTest, { test, assert } from '@sprucelabs/test-utils'
2
- import PackageJsonUpdater, {
3
- JsonUpdater,
4
- } from '../../modules/PackageJsonUpdater'
5
-
6
- export default class PackageJsonUpdaterTest extends AbstractSpruceTest {
7
- private static instance: JsonUpdater
8
-
9
- protected static async beforeEach() {
10
- await super.beforeEach()
11
-
12
- this.instance = this.PackageJsonUpdater()
13
- }
14
-
15
- @test()
16
- protected static async createsInstance() {
17
- assert.isTruthy(this.instance, 'Failed to create instance!')
18
- }
19
-
20
- private static PackageJsonUpdater() {
21
- return PackageJsonUpdater.Create()
22
- }
23
- }
@@ -1,13 +0,0 @@
1
- export default class PackageJsonUpdater implements JsonUpdater {
2
- public static Class?: JsonUpdateConstructor
3
-
4
- protected constructor() {}
5
-
6
- public static Create() {
7
- return new (this.Class ?? this)()
8
- }
9
- }
10
-
11
- export interface JsonUpdater {}
12
-
13
- export type JsonUpdateConstructor = new () => JsonUpdater