@thegetty/quire-cli 1.0.0-rc.45 → 1.0.0-rc.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -36
- package/README.md +0 -9
- package/bin/cli.js +1 -46
- package/package.json +10 -27
- package/src/Command.js +6 -26
- package/src/commands/README.md +122 -213
- package/src/commands/build.js +37 -45
- package/src/commands/clean.js +19 -33
- package/src/commands/conf.js +43 -0
- package/src/commands/create.js +14 -42
- package/src/commands/epub.js +31 -67
- package/src/commands/index.js +2 -9
- package/src/commands/info.js +86 -88
- package/src/commands/pdf.js +82 -63
- package/src/commands/preview.js +31 -32
- package/src/commands/validate.js +20 -64
- package/src/commands/version.js +43 -0
- package/src/errors/validation/validation-error.js +11 -20
- package/src/helpers/clean.js +1 -1
- package/src/helpers/is-quire.js +31 -0
- package/src/helpers/test-cwd.js +6 -5
- package/src/helpers/which.js +4 -10
- package/src/lib/11ty/README.md +19 -135
- package/src/lib/11ty/api.js +93 -235
- package/src/lib/11ty/cli.js +37 -112
- package/src/lib/11ty/index.js +5 -64
- package/src/lib/11ty/paths.js +103 -0
- package/src/lib/README.md +0 -330
- package/src/lib/conf/README.md +69 -86
- package/src/lib/conf/config.js +3 -5
- package/src/lib/conf/defaults.js +0 -65
- package/src/lib/conf/schema.js +9 -103
- package/src/lib/epub/README.md +2 -133
- package/src/lib/epub/epub.js +11 -36
- package/src/lib/epub/index.js +21 -111
- package/src/lib/epub/pandoc.js +4 -33
- package/src/lib/git/README.md +2 -151
- package/src/lib/git/index.js +13 -217
- package/src/lib/i18n/README.md +3 -0
- package/src/lib/i18n/config.js +53 -0
- package/src/lib/i18n/index.js +43 -0
- package/src/lib/i18n/localeService.js +58 -0
- package/src/lib/pdf/README.md +0 -131
- package/src/lib/pdf/index.js +21 -124
- package/src/lib/pdf/paged.js +52 -100
- package/src/lib/pdf/prince.js +37 -115
- package/src/lib/pdf/split.js +33 -61
- package/src/lib/quire/README.md +19 -0
- package/src/lib/quire/index.js +353 -0
- package/src/lib/reporter/README.md +2 -211
- package/src/lib/reporter/index.js +0 -607
- package/src/main.js +48 -221
- package/src/packageConfig.js +0 -17
- package/src/validators/utils.js +1 -2
- package/man/quire.1 +0 -341
- package/man/quire.1.md +0 -232
- package/schemas/config.schema.json +0 -194
- package/schemas/figures.schema.json +0 -56
- package/schemas/layout.schema.json +0 -5
- package/schemas/objects.schema.json +0 -62
- package/schemas/publication.schema.json +0 -140
- package/schemas/references.schema.json +0 -29
- package/src/Command.spec.js +0 -99
- package/src/commands/build.spec.js +0 -113
- package/src/commands/build.test.js +0 -397
- package/src/commands/clean.spec.js +0 -118
- package/src/commands/clean.test.js +0 -382
- package/src/commands/config.js +0 -238
- package/src/commands/config.spec.js +0 -107
- package/src/commands/config.test.js +0 -845
- package/src/commands/create.spec.js +0 -112
- package/src/commands/create.test.js +0 -415
- package/src/commands/doctor.js +0 -251
- package/src/commands/doctor.spec.js +0 -115
- package/src/commands/doctor.test.js +0 -1409
- package/src/commands/epub.spec.js +0 -114
- package/src/commands/epub.test.js +0 -503
- package/src/commands/help.js +0 -60
- package/src/commands/help.test.js +0 -132
- package/src/commands/info.spec.js +0 -72
- package/src/commands/info.test.js +0 -512
- package/src/commands/pdf.spec.js +0 -114
- package/src/commands/pdf.test.js +0 -464
- package/src/commands/preview.spec.js +0 -97
- package/src/commands/preview.test.js +0 -250
- package/src/commands/use.js +0 -56
- package/src/commands/use.spec.js +0 -61
- package/src/commands/use.test.js +0 -280
- package/src/commands/validate.spec.js +0 -90
- package/src/commands/validate.test.js +0 -378
- package/src/commands/workflows.js +0 -70
- package/src/errors/build/build-failed-error.js +0 -19
- package/src/errors/build/config-field-missing-error.js +0 -20
- package/src/errors/build/config-file-not-found-error.js +0 -20
- package/src/errors/build/index.js +0 -11
- package/src/errors/help/help-topic-not-found-error.js +0 -30
- package/src/errors/help/index.js +0 -8
- package/src/errors/index.js +0 -58
- package/src/errors/input/index.js +0 -8
- package/src/errors/input/invalid-input-error.js +0 -21
- package/src/errors/install/dependency-install-error.js +0 -19
- package/src/errors/install/directory-not-empty-error.js +0 -25
- package/src/errors/install/index.js +0 -12
- package/src/errors/install/invalid-path-error.js +0 -31
- package/src/errors/install/invalid-starter-error.js +0 -27
- package/src/errors/install/version-not-found-error.js +0 -35
- package/src/errors/output/epub-generation-error.js +0 -19
- package/src/errors/output/index.js +0 -14
- package/src/errors/output/invalid-epub-library-error.js +0 -20
- package/src/errors/output/invalid-pdf-library-error.js +0 -20
- package/src/errors/output/missing-build-output-error.js +0 -21
- package/src/errors/output/pdf-generation-error.js +0 -24
- package/src/errors/output/tool-not-found-error.js +0 -37
- package/src/errors/project/index.js +0 -10
- package/src/errors/project/not-in-project-error.js +0 -20
- package/src/errors/project/project-create-error.js +0 -21
- package/src/errors/quire-error.js +0 -27
- package/src/errors/validation/index.js +0 -3
- package/src/errors/validation/unknown-config-key-error.js +0 -27
- package/src/errors/validation/unknown-config-operation-error.js +0 -24
- package/src/helpers/docs-url.js +0 -32
- package/src/helpers/pager.js +0 -59
- package/src/helpers/pager.test.js +0 -85
- package/src/helpers/suggest-similar.js +0 -124
- package/src/helpers/suggest-similar.test.js +0 -108
- package/src/helpers/test-cwd.test.js +0 -192
- package/src/lib/11ty/index.test.js +0 -655
- package/src/lib/commander/index.js +0 -103
- package/src/lib/commander/index.test.js +0 -86
- package/src/lib/commander/options.js +0 -237
- package/src/lib/commander/options.test.js +0 -205
- package/src/lib/conf/build-status.js +0 -103
- package/src/lib/conf/build-status.test.js +0 -247
- package/src/lib/conf/config.test.js +0 -281
- package/src/lib/conf/format.js +0 -60
- package/src/lib/conf/format.test.js +0 -106
- package/src/lib/conf/helpers.js +0 -91
- package/src/lib/conf/helpers.test.js +0 -136
- package/src/lib/conf/index.js +0 -22
- package/src/lib/constants.js +0 -28
- package/src/lib/doctor/README.md +0 -667
- package/src/lib/doctor/checks/environment/cli-version.js +0 -62
- package/src/lib/doctor/checks/environment/cli-version.test.js +0 -132
- package/src/lib/doctor/checks/environment/git-available.js +0 -77
- package/src/lib/doctor/checks/environment/git-available.test.js +0 -52
- package/src/lib/doctor/checks/environment/index.js +0 -13
- package/src/lib/doctor/checks/environment/node-version.js +0 -66
- package/src/lib/doctor/checks/environment/node-version.test.js +0 -17
- package/src/lib/doctor/checks/environment/npm-available.js +0 -66
- package/src/lib/doctor/checks/environment/npm-available.test.js +0 -52
- package/src/lib/doctor/checks/environment/os-info.js +0 -48
- package/src/lib/doctor/checks/environment/os-info.test.js +0 -81
- package/src/lib/doctor/checks/environment/runtime-info.js +0 -51
- package/src/lib/doctor/checks/environment/runtime-info.test.js +0 -132
- package/src/lib/doctor/checks/outputs/epub-output.js +0 -119
- package/src/lib/doctor/checks/outputs/epub-output.test.js +0 -277
- package/src/lib/doctor/checks/outputs/index.js +0 -10
- package/src/lib/doctor/checks/outputs/pdf-output.js +0 -144
- package/src/lib/doctor/checks/outputs/pdf-output.test.js +0 -377
- package/src/lib/doctor/checks/outputs/stale-build.js +0 -122
- package/src/lib/doctor/checks/outputs/stale-build.test.js +0 -282
- package/src/lib/doctor/checks/project/data-files.js +0 -56
- package/src/lib/doctor/checks/project/data-files.test.js +0 -125
- package/src/lib/doctor/checks/project/dependencies.js +0 -53
- package/src/lib/doctor/checks/project/dependencies.test.js +0 -71
- package/src/lib/doctor/checks/project/index.js +0 -11
- package/src/lib/doctor/checks/project/quire-11ty.js +0 -98
- package/src/lib/doctor/checks/project/quire-11ty.test.js +0 -170
- package/src/lib/doctor/checks/project/quire-project.js +0 -38
- package/src/lib/doctor/checks/project/quire-project.test.js +0 -47
- package/src/lib/doctor/checks/tools/index.js +0 -10
- package/src/lib/doctor/checks/tools/pandoc-available.js +0 -82
- package/src/lib/doctor/checks/tools/pandoc-available.test.js +0 -73
- package/src/lib/doctor/checks/tools/prince-available.js +0 -81
- package/src/lib/doctor/checks/tools/prince-available.test.js +0 -73
- package/src/lib/doctor/constants.js +0 -39
- package/src/lib/doctor/formatDuration.js +0 -108
- package/src/lib/doctor/formatDuration.test.js +0 -76
- package/src/lib/doctor/formatters/human.js +0 -257
- package/src/lib/doctor/formatters/human.test.js +0 -463
- package/src/lib/doctor/formatters/index.js +0 -8
- package/src/lib/doctor/formatters/json.js +0 -78
- package/src/lib/doctor/formatters/json.test.js +0 -174
- package/src/lib/doctor/formatters/shared.js +0 -129
- package/src/lib/doctor/formatters/shared.test.js +0 -194
- package/src/lib/doctor/index.js +0 -271
- package/src/lib/doctor/index.test.js +0 -797
- package/src/lib/epub/engines.js +0 -46
- package/src/lib/epub/index.test.js +0 -518
- package/src/lib/epub/pandoc.test.js +0 -122
- package/src/lib/epub/schema.js +0 -21
- package/src/lib/error/README.md +0 -170
- package/src/lib/error/handler.js +0 -107
- package/src/lib/git/index.spec.js +0 -80
- package/src/lib/git/index.test.js +0 -453
- package/src/lib/help/frontmatter.js +0 -77
- package/src/lib/help/frontmatter.test.js +0 -139
- package/src/lib/help/index.js +0 -146
- package/src/lib/help/index.test.js +0 -188
- package/src/lib/help/topics/configuration.md +0 -77
- package/src/lib/help/topics/debugging.md +0 -69
- package/src/lib/help/topics/epub.md +0 -74
- package/src/lib/help/topics/pdf.md +0 -74
- package/src/lib/help/topics/publishing.md +0 -80
- package/src/lib/help/topics/workflows.md +0 -50
- package/src/lib/installer/index.js +0 -309
- package/src/lib/installer/index.spec.js +0 -83
- package/src/lib/installer/index.test.js +0 -545
- package/src/lib/logger/README.md +0 -424
- package/src/lib/logger/debug.js +0 -132
- package/src/lib/logger/debug.spec.js +0 -130
- package/src/lib/logger/debug.test.js +0 -128
- package/src/lib/logger/index.js +0 -228
- package/src/lib/logger/index.spec.js +0 -131
- package/src/lib/logger/index.test.js +0 -578
- package/src/lib/npm/README.md +0 -127
- package/src/lib/npm/index.js +0 -198
- package/src/lib/npm/index.spec.js +0 -60
- package/src/lib/npm/index.test.js +0 -355
- package/src/lib/pdf/engines.js +0 -46
- package/src/lib/pdf/index.test.js +0 -708
- package/src/lib/pdf/paged.test.js +0 -366
- package/src/lib/pdf/prince.test.js +0 -202
- package/src/lib/pdf/schema.js +0 -21
- package/src/lib/pdf/split.test.js +0 -445
- package/src/lib/platform.js +0 -95
- package/src/lib/process/manager.js +0 -110
- package/src/lib/process/manager.test.js +0 -55
- package/src/lib/project/build.js +0 -162
- package/src/lib/project/build.test.js +0 -275
- package/src/lib/project/config.js +0 -48
- package/src/lib/project/config.test.js +0 -134
- package/src/lib/project/detect.js +0 -47
- package/src/lib/project/detect.test.js +0 -157
- package/src/lib/project/index.js +0 -56
- package/src/lib/project/output-paths.js +0 -87
- package/src/lib/project/output-paths.test.js +0 -66
- package/src/lib/project/paths.js +0 -272
- package/src/lib/project/version.js +0 -110
- package/src/lib/project/version.test.js +0 -350
- package/src/lib/reporter/index.test.js +0 -862
- package/src/main.spec.js +0 -61
- package/src/main.test.js +0 -347
- package/src/validators/validate-data-files.js +0 -154
- package/src/validators/validate-data-files.test.js +0 -217
|
@@ -1,453 +0,0 @@
|
|
|
1
|
-
import esmock from 'esmock'
|
|
2
|
-
import sinon from 'sinon'
|
|
3
|
-
import test from 'ava'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Git Façade Integration Tests
|
|
7
|
-
*
|
|
8
|
-
* Tests the git façade module behavior with mocked dependencies.
|
|
9
|
-
* Uses esmock to replace execa calls.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
test.beforeEach((t) => {
|
|
13
|
-
t.context.sandbox = sinon.createSandbox()
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
test.afterEach.always((t) => {
|
|
17
|
-
t.context.sandbox.restore()
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
// Singleton tests (default export, no cwd)
|
|
21
|
-
test('singleton add() stages files without cwd', async (t) => {
|
|
22
|
-
const { sandbox } = t.context
|
|
23
|
-
|
|
24
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
25
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
26
|
-
|
|
27
|
-
const git = await esmock('./index.js', {
|
|
28
|
-
execa: { execa: mockExeca },
|
|
29
|
-
'#helpers/which.js': { default: mockWhich },
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
await git.add('file.js')
|
|
33
|
-
|
|
34
|
-
t.true(mockExeca.calledOnce)
|
|
35
|
-
t.true(mockExeca.calledWith('git', ['add', 'file.js'], {}))
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test('singleton clone() uses empty options', async (t) => {
|
|
39
|
-
const { sandbox } = t.context
|
|
40
|
-
|
|
41
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
42
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
43
|
-
|
|
44
|
-
const git = await esmock('./index.js', {
|
|
45
|
-
execa: { execa: mockExeca },
|
|
46
|
-
'#helpers/which.js': { default: mockWhich },
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
await git.clone('https://github.com/user/repo')
|
|
50
|
-
|
|
51
|
-
t.true(mockExeca.calledWith('git', ['clone', 'https://github.com/user/repo', '.'], {}))
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('singleton init() uses empty options', async (t) => {
|
|
55
|
-
const { sandbox } = t.context
|
|
56
|
-
|
|
57
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
58
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
59
|
-
|
|
60
|
-
const git = await esmock('./index.js', {
|
|
61
|
-
execa: { execa: mockExeca },
|
|
62
|
-
'#helpers/which.js': { default: mockWhich },
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
await git.init()
|
|
66
|
-
|
|
67
|
-
t.true(mockExeca.calledWith('git', ['init'], {}))
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
// Git class instance tests (with cwd)
|
|
71
|
-
test('instance add() stages single file with cwd', async (t) => {
|
|
72
|
-
const { sandbox } = t.context
|
|
73
|
-
|
|
74
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
75
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
76
|
-
|
|
77
|
-
const { Git } = await esmock('./index.js', {
|
|
78
|
-
execa: { execa: mockExeca },
|
|
79
|
-
'#helpers/which.js': { default: mockWhich },
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
const repo = new Git('/path/to/project')
|
|
83
|
-
await repo.add('file.js')
|
|
84
|
-
|
|
85
|
-
t.true(mockExeca.calledOnce)
|
|
86
|
-
t.true(mockExeca.calledWith('git', ['add', 'file.js'], { cwd: '/path/to/project' }))
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
test('instance add() stages multiple files', async (t) => {
|
|
90
|
-
const { sandbox } = t.context
|
|
91
|
-
|
|
92
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
93
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
94
|
-
|
|
95
|
-
const { Git } = await esmock('./index.js', {
|
|
96
|
-
execa: { execa: mockExeca },
|
|
97
|
-
'#helpers/which.js': { default: mockWhich },
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
const repo = new Git('/path/to/project')
|
|
101
|
-
await repo.add(['file1.js', 'file2.js'])
|
|
102
|
-
|
|
103
|
-
t.true(mockExeca.calledWith('git', ['add', 'file1.js', 'file2.js'], { cwd: '/path/to/project' }))
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
test('instance add() stages all files with dot notation', async (t) => {
|
|
107
|
-
const { sandbox } = t.context
|
|
108
|
-
|
|
109
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
110
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
111
|
-
|
|
112
|
-
const { Git } = await esmock('./index.js', {
|
|
113
|
-
execa: { execa: mockExeca },
|
|
114
|
-
'#helpers/which.js': { default: mockWhich },
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
const repo = new Git('/path/to/project')
|
|
118
|
-
await repo.add('.')
|
|
119
|
-
|
|
120
|
-
t.true(mockExeca.calledWith('git', ['add', '.'], { cwd: '/path/to/project' }))
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
test('instance clone() clones repository to destination', async (t) => {
|
|
124
|
-
const { sandbox } = t.context
|
|
125
|
-
|
|
126
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
127
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
128
|
-
|
|
129
|
-
const { Git } = await esmock('./index.js', {
|
|
130
|
-
execa: { execa: mockExeca },
|
|
131
|
-
'#helpers/which.js': { default: mockWhich },
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
const repo = new Git('/path/to/parent')
|
|
135
|
-
await repo.clone('https://github.com/user/repo', 'dest')
|
|
136
|
-
|
|
137
|
-
t.true(mockExeca.calledOnce)
|
|
138
|
-
t.true(mockExeca.calledWith('git', ['clone', 'https://github.com/user/repo', 'dest'], { cwd: '/path/to/parent' }))
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
test('instance clone() uses current directory as default destination', async (t) => {
|
|
142
|
-
const { sandbox } = t.context
|
|
143
|
-
|
|
144
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
145
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
146
|
-
|
|
147
|
-
const { Git } = await esmock('./index.js', {
|
|
148
|
-
execa: { execa: mockExeca },
|
|
149
|
-
'#helpers/which.js': { default: mockWhich },
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
const repo = new Git('/path/to/parent')
|
|
153
|
-
await repo.clone('https://github.com/user/repo')
|
|
154
|
-
|
|
155
|
-
t.true(mockExeca.calledWith('git', ['clone', 'https://github.com/user/repo', '.'], { cwd: '/path/to/parent' }))
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
test('instance commit() creates commit with message', async (t) => {
|
|
159
|
-
const { sandbox } = t.context
|
|
160
|
-
|
|
161
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
162
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
163
|
-
|
|
164
|
-
const { Git } = await esmock('./index.js', {
|
|
165
|
-
execa: { execa: mockExeca },
|
|
166
|
-
'#helpers/which.js': { default: mockWhich },
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
const repo = new Git('/path/to/project')
|
|
170
|
-
await repo.commit('Initial commit')
|
|
171
|
-
|
|
172
|
-
t.true(mockExeca.calledOnce)
|
|
173
|
-
t.true(mockExeca.calledWith('git', ['commit', '-m', 'Initial commit'], { cwd: '/path/to/project' }))
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
test('instance init() initializes repository', async (t) => {
|
|
177
|
-
const { sandbox } = t.context
|
|
178
|
-
|
|
179
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
180
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
181
|
-
|
|
182
|
-
const { Git } = await esmock('./index.js', {
|
|
183
|
-
execa: { execa: mockExeca },
|
|
184
|
-
'#helpers/which.js': { default: mockWhich },
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
const repo = new Git('/path/to/project')
|
|
188
|
-
await repo.init()
|
|
189
|
-
|
|
190
|
-
t.true(mockExeca.calledOnce)
|
|
191
|
-
t.true(mockExeca.calledWith('git', ['init'], { cwd: '/path/to/project' }))
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
test('instance rm() removes single file', async (t) => {
|
|
195
|
-
const { sandbox } = t.context
|
|
196
|
-
|
|
197
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
198
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
199
|
-
|
|
200
|
-
const { Git } = await esmock('./index.js', {
|
|
201
|
-
execa: { execa: mockExeca },
|
|
202
|
-
'#helpers/which.js': { default: mockWhich },
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
const repo = new Git('/path/to/project')
|
|
206
|
-
await repo.rm('package.json')
|
|
207
|
-
|
|
208
|
-
t.true(mockExeca.calledOnce)
|
|
209
|
-
t.true(mockExeca.calledWith('git', ['rm', 'package.json'], { cwd: '/path/to/project' }))
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
test('instance rm() removes multiple files', async (t) => {
|
|
213
|
-
const { sandbox } = t.context
|
|
214
|
-
|
|
215
|
-
const mockExeca = sandbox.stub().resolves({})
|
|
216
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
217
|
-
|
|
218
|
-
const { Git } = await esmock('./index.js', {
|
|
219
|
-
execa: { execa: mockExeca },
|
|
220
|
-
'#helpers/which.js': { default: mockWhich },
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
const repo = new Git('/path/to/project')
|
|
224
|
-
await repo.rm(['file1.js', 'file2.js'])
|
|
225
|
-
|
|
226
|
-
t.true(mockExeca.calledWith('git', ['rm', 'file1.js', 'file2.js'], { cwd: '/path/to/project' }))
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
// Global methods (work same on singleton or instance)
|
|
230
|
-
test('version() returns git version string', async (t) => {
|
|
231
|
-
const { sandbox } = t.context
|
|
232
|
-
|
|
233
|
-
const mockExeca = sandbox.stub().resolves({ stdout: 'git version 2.39.0' })
|
|
234
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
235
|
-
|
|
236
|
-
const git = await esmock('./index.js', {
|
|
237
|
-
execa: { execa: mockExeca },
|
|
238
|
-
'#helpers/which.js': { default: mockWhich },
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
const result = await git.version()
|
|
242
|
-
|
|
243
|
-
t.is(result, '2.39.0')
|
|
244
|
-
t.true(mockExeca.calledWith('git', ['--version']))
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
test('isAvailable() returns true when git is found in PATH', async (t) => {
|
|
248
|
-
const { sandbox } = t.context
|
|
249
|
-
|
|
250
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
251
|
-
|
|
252
|
-
const git = await esmock('./index.js', {
|
|
253
|
-
execa: { execa: sandbox.stub() },
|
|
254
|
-
'#helpers/which.js': { default: mockWhich },
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
const result = git.isAvailable()
|
|
258
|
-
|
|
259
|
-
t.true(result)
|
|
260
|
-
t.true(mockWhich.calledWith('git'))
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
test('isAvailable() returns false when git is not found in PATH', async (t) => {
|
|
264
|
-
const { sandbox } = t.context
|
|
265
|
-
|
|
266
|
-
const mockWhich = sandbox.stub().returns(null)
|
|
267
|
-
|
|
268
|
-
const git = await esmock('./index.js', {
|
|
269
|
-
execa: { execa: sandbox.stub() },
|
|
270
|
-
'#helpers/which.js': { default: mockWhich },
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
const result = git.isAvailable()
|
|
274
|
-
|
|
275
|
-
t.false(result)
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
test('instance add() logs stderr via debug when present', async (t) => {
|
|
279
|
-
const { sandbox } = t.context
|
|
280
|
-
|
|
281
|
-
const mockExeca = sandbox.stub().resolves({ stderr: 'warning: LF will be replaced by CRLF' })
|
|
282
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
283
|
-
const mockDebug = sandbox.stub()
|
|
284
|
-
const mockCreateDebug = sandbox.stub().returns(mockDebug)
|
|
285
|
-
|
|
286
|
-
const { Git } = await esmock('./index.js', {
|
|
287
|
-
execa: { execa: mockExeca },
|
|
288
|
-
'#helpers/which.js': { default: mockWhich },
|
|
289
|
-
'#debug': { default: mockCreateDebug }
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
const repo = new Git('/path/to/project')
|
|
293
|
-
await repo.add('file.js')
|
|
294
|
-
|
|
295
|
-
t.true(mockDebug.calledWith('git add stderr: %s', 'warning: LF will be replaced by CRLF'))
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
test('instance commit() logs stderr via debug when present', async (t) => {
|
|
299
|
-
const { sandbox } = t.context
|
|
300
|
-
|
|
301
|
-
const mockExeca = sandbox.stub().resolves({ stderr: '[main abc1234] commit message' })
|
|
302
|
-
const mockWhich = sandbox.stub().returns('/usr/bin/git')
|
|
303
|
-
const mockDebug = sandbox.stub()
|
|
304
|
-
const mockCreateDebug = sandbox.stub().returns(mockDebug)
|
|
305
|
-
|
|
306
|
-
const { Git } = await esmock('./index.js', {
|
|
307
|
-
execa: { execa: mockExeca },
|
|
308
|
-
'#helpers/which.js': { default: mockWhich },
|
|
309
|
-
'#debug': { default: mockCreateDebug }
|
|
310
|
-
})
|
|
311
|
-
|
|
312
|
-
const repo = new Git('/path/to/project')
|
|
313
|
-
await repo.commit('test commit')
|
|
314
|
-
|
|
315
|
-
t.true(mockDebug.calledWith('git commit stderr: %s', '[main abc1234] commit message'))
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
// isRemoteUrl() tests
|
|
319
|
-
test('isRemoteUrl() returns true for https URLs', async (t) => {
|
|
320
|
-
const { isRemoteUrl } = await import('./index.js')
|
|
321
|
-
|
|
322
|
-
t.true(isRemoteUrl('https://github.com/user/repo'))
|
|
323
|
-
t.true(isRemoteUrl('https://github.com/user/repo.git'))
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
test('isRemoteUrl() returns true for http URLs', async (t) => {
|
|
327
|
-
const { isRemoteUrl } = await import('./index.js')
|
|
328
|
-
|
|
329
|
-
t.true(isRemoteUrl('http://github.com/user/repo'))
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
test('isRemoteUrl() returns true for git@ SSH URLs', async (t) => {
|
|
333
|
-
const { isRemoteUrl } = await import('./index.js')
|
|
334
|
-
|
|
335
|
-
t.true(isRemoteUrl('git@github.com:user/repo.git'))
|
|
336
|
-
t.true(isRemoteUrl('git@gitlab.com:user/repo'))
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
test('isRemoteUrl() returns true for ssh:// URLs', async (t) => {
|
|
340
|
-
const { isRemoteUrl } = await import('./index.js')
|
|
341
|
-
|
|
342
|
-
t.true(isRemoteUrl('ssh://git@github.com/user/repo.git'))
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
test('isRemoteUrl() returns true for git:// URLs', async (t) => {
|
|
346
|
-
const { isRemoteUrl } = await import('./index.js')
|
|
347
|
-
|
|
348
|
-
t.true(isRemoteUrl('git://github.com/user/repo.git'))
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
test('isRemoteUrl() returns false for local paths', async (t) => {
|
|
352
|
-
const { isRemoteUrl } = await import('./index.js')
|
|
353
|
-
|
|
354
|
-
t.false(isRemoteUrl('/path/to/local/repo'))
|
|
355
|
-
t.false(isRemoteUrl('./relative/path'))
|
|
356
|
-
t.false(isRemoteUrl('../parent/path'))
|
|
357
|
-
t.false(isRemoteUrl('local-folder'))
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
// isGitRepository() tests
|
|
361
|
-
test('isGitRepository() returns true when .git directory exists', async (t) => {
|
|
362
|
-
const { sandbox } = t.context
|
|
363
|
-
|
|
364
|
-
const mockFs = {
|
|
365
|
-
existsSync: sandbox.stub().returns(true)
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
const { isGitRepository } = await esmock('./index.js', {
|
|
369
|
-
'node:fs': mockFs
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
const result = isGitRepository('/path/to/repo')
|
|
373
|
-
|
|
374
|
-
t.true(result)
|
|
375
|
-
t.true(mockFs.existsSync.calledOnce)
|
|
376
|
-
})
|
|
377
|
-
|
|
378
|
-
test('isGitRepository() returns false when .git directory does not exist', async (t) => {
|
|
379
|
-
const { sandbox } = t.context
|
|
380
|
-
|
|
381
|
-
const mockFs = {
|
|
382
|
-
existsSync: sandbox.stub().returns(false)
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
const { isGitRepository } = await esmock('./index.js', {
|
|
386
|
-
'node:fs': mockFs
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
const result = isGitRepository('/path/without/git')
|
|
390
|
-
|
|
391
|
-
t.false(result)
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
// validateCloneSource() tests
|
|
395
|
-
test('validateCloneSource() returns valid for remote URLs', async (t) => {
|
|
396
|
-
const { validateCloneSource } = await import('./index.js')
|
|
397
|
-
|
|
398
|
-
t.deepEqual(validateCloneSource('https://github.com/user/repo'), { valid: true })
|
|
399
|
-
t.deepEqual(validateCloneSource('git@github.com:user/repo.git'), { valid: true })
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
test('validateCloneSource() returns invalid when local path does not exist', async (t) => {
|
|
403
|
-
const { sandbox } = t.context
|
|
404
|
-
|
|
405
|
-
const mockFs = {
|
|
406
|
-
existsSync: sandbox.stub().returns(false)
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const { validateCloneSource } = await esmock('./index.js', {
|
|
410
|
-
'node:fs': mockFs
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
const result = validateCloneSource('/nonexistent/path')
|
|
414
|
-
|
|
415
|
-
t.false(result.valid)
|
|
416
|
-
t.is(result.reason, 'path does not exist')
|
|
417
|
-
})
|
|
418
|
-
|
|
419
|
-
test('validateCloneSource() returns invalid when path is not a git repository', async (t) => {
|
|
420
|
-
const { sandbox } = t.context
|
|
421
|
-
|
|
422
|
-
const mockFs = {
|
|
423
|
-
existsSync: sandbox.stub()
|
|
424
|
-
.onFirstCall().returns(true) // path exists
|
|
425
|
-
.onSecondCall().returns(false) // .git does not exist
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
const { validateCloneSource } = await esmock('./index.js', {
|
|
429
|
-
'node:fs': mockFs
|
|
430
|
-
})
|
|
431
|
-
|
|
432
|
-
const result = validateCloneSource('/path/without/git')
|
|
433
|
-
|
|
434
|
-
t.false(result.valid)
|
|
435
|
-
t.is(result.reason, 'not a git repository')
|
|
436
|
-
})
|
|
437
|
-
|
|
438
|
-
test('validateCloneSource() returns valid for local git repository', async (t) => {
|
|
439
|
-
const { sandbox } = t.context
|
|
440
|
-
|
|
441
|
-
const mockFs = {
|
|
442
|
-
existsSync: sandbox.stub().returns(true) // both path and .git exist
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const { validateCloneSource } = await esmock('./index.js', {
|
|
446
|
-
'node:fs': mockFs
|
|
447
|
-
})
|
|
448
|
-
|
|
449
|
-
const result = validateCloneSource('/path/to/repo')
|
|
450
|
-
|
|
451
|
-
t.true(result.valid)
|
|
452
|
-
t.is(result.reason, undefined)
|
|
453
|
-
})
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* YAML frontmatter parsing utilities
|
|
3
|
-
*
|
|
4
|
-
* Extracts and strips YAML frontmatter from markdown content.
|
|
5
|
-
* Frontmatter is delimited by `---` on its own line.
|
|
6
|
-
*
|
|
7
|
-
* @module lib/help/frontmatter
|
|
8
|
-
*/
|
|
9
|
-
import yaml from 'js-yaml'
|
|
10
|
-
|
|
11
|
-
/** Regex to match YAML frontmatter block */
|
|
12
|
-
const FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Extract YAML frontmatter from markdown content
|
|
16
|
-
*
|
|
17
|
-
* @param {string} content - Markdown content with optional frontmatter
|
|
18
|
-
* @returns {Object} Parsed frontmatter data or empty object if none/invalid
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* const meta = extractFrontmatter(`---
|
|
22
|
-
* title: My Topic
|
|
23
|
-
* description: A description
|
|
24
|
-
* ---
|
|
25
|
-
* # Content`)
|
|
26
|
-
* // => { title: 'My Topic', description: 'A description' }
|
|
27
|
-
*/
|
|
28
|
-
export function extractFrontmatter(content) {
|
|
29
|
-
const match = content.match(FRONTMATTER_REGEX)
|
|
30
|
-
if (!match) return {}
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
return yaml.load(match[1]) || {}
|
|
34
|
-
} catch {
|
|
35
|
-
return {}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Strip YAML frontmatter from markdown content
|
|
41
|
-
*
|
|
42
|
-
* @param {string} content - Markdown content with optional frontmatter
|
|
43
|
-
* @returns {string} Content without frontmatter block
|
|
44
|
-
*
|
|
45
|
-
* @example
|
|
46
|
-
* const body = stripFrontmatter(`---
|
|
47
|
-
* title: My Topic
|
|
48
|
-
* ---
|
|
49
|
-
* # Content`)
|
|
50
|
-
* // => '# Content'
|
|
51
|
-
*/
|
|
52
|
-
export function stripFrontmatter(content) {
|
|
53
|
-
return content.replace(/^---\n[\s\S]*?\n---\n?/, '')
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Parse markdown content with frontmatter
|
|
58
|
-
*
|
|
59
|
-
* Convenience function that returns both metadata and content body.
|
|
60
|
-
*
|
|
61
|
-
* @param {string} content - Markdown content with optional frontmatter
|
|
62
|
-
* @returns {{ data: Object, content: string }} Parsed frontmatter and body
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* const { data, content } = parseFrontmatter(`---
|
|
66
|
-
* title: My Topic
|
|
67
|
-
* ---
|
|
68
|
-
* # Content`)
|
|
69
|
-
* // data => { title: 'My Topic' }
|
|
70
|
-
* // content => '# Content'
|
|
71
|
-
*/
|
|
72
|
-
export function parseFrontmatter(content) {
|
|
73
|
-
return {
|
|
74
|
-
data: extractFrontmatter(content),
|
|
75
|
-
content: stripFrontmatter(content)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import test from 'ava'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
extractFrontmatter,
|
|
5
|
-
stripFrontmatter,
|
|
6
|
-
parseFrontmatter
|
|
7
|
-
} from './frontmatter.js'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Frontmatter Parsing Tests
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// extractFrontmatter tests
|
|
14
|
-
|
|
15
|
-
test('extractFrontmatter() returns parsed YAML data', (t) => {
|
|
16
|
-
const content = `---
|
|
17
|
-
title: Test Topic
|
|
18
|
-
description: A test description
|
|
19
|
-
---
|
|
20
|
-
# Content`
|
|
21
|
-
|
|
22
|
-
const result = extractFrontmatter(content)
|
|
23
|
-
|
|
24
|
-
t.deepEqual(result, {
|
|
25
|
-
title: 'Test Topic',
|
|
26
|
-
description: 'A test description'
|
|
27
|
-
})
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('extractFrontmatter() returns empty object when no frontmatter', (t) => {
|
|
31
|
-
const content = '# Just Content\n\nNo frontmatter here.'
|
|
32
|
-
|
|
33
|
-
const result = extractFrontmatter(content)
|
|
34
|
-
|
|
35
|
-
t.deepEqual(result, {})
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test('extractFrontmatter() returns empty object for invalid YAML', (t) => {
|
|
39
|
-
const content = `---
|
|
40
|
-
title: [invalid yaml
|
|
41
|
-
---
|
|
42
|
-
# Content`
|
|
43
|
-
|
|
44
|
-
const result = extractFrontmatter(content)
|
|
45
|
-
|
|
46
|
-
t.deepEqual(result, {})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
test('extractFrontmatter() handles values containing colons', (t) => {
|
|
50
|
-
const content = `---
|
|
51
|
-
url: https://example.com/path
|
|
52
|
-
title: "Part 1: Introduction"
|
|
53
|
-
---
|
|
54
|
-
# Content`
|
|
55
|
-
|
|
56
|
-
const result = extractFrontmatter(content)
|
|
57
|
-
|
|
58
|
-
t.is(result.url, 'https://example.com/path')
|
|
59
|
-
t.is(result.title, 'Part 1: Introduction')
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test('extractFrontmatter() handles arrays and nested objects', (t) => {
|
|
63
|
-
const content = `---
|
|
64
|
-
tags:
|
|
65
|
-
- one
|
|
66
|
-
- two
|
|
67
|
-
author:
|
|
68
|
-
name: Test
|
|
69
|
-
email: test@example.com
|
|
70
|
-
---
|
|
71
|
-
# Content`
|
|
72
|
-
|
|
73
|
-
const result = extractFrontmatter(content)
|
|
74
|
-
|
|
75
|
-
t.deepEqual(result.tags, ['one', 'two'])
|
|
76
|
-
t.deepEqual(result.author, { name: 'Test', email: 'test@example.com' })
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
// stripFrontmatter tests
|
|
80
|
-
|
|
81
|
-
test('stripFrontmatter() removes frontmatter block', (t) => {
|
|
82
|
-
const content = `---
|
|
83
|
-
title: Test
|
|
84
|
-
---
|
|
85
|
-
# Content
|
|
86
|
-
|
|
87
|
-
Body text.`
|
|
88
|
-
|
|
89
|
-
const result = stripFrontmatter(content)
|
|
90
|
-
|
|
91
|
-
t.is(result, '# Content\n\nBody text.')
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
test('stripFrontmatter() returns content unchanged when no frontmatter', (t) => {
|
|
95
|
-
const content = '# Just Content\n\nNo frontmatter.'
|
|
96
|
-
|
|
97
|
-
const result = stripFrontmatter(content)
|
|
98
|
-
|
|
99
|
-
t.is(result, content)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
test('stripFrontmatter() handles frontmatter without trailing newline', (t) => {
|
|
103
|
-
const content = `---
|
|
104
|
-
title: Test
|
|
105
|
-
---# Content`
|
|
106
|
-
|
|
107
|
-
const result = stripFrontmatter(content)
|
|
108
|
-
|
|
109
|
-
t.is(result, '# Content')
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// parseFrontmatter tests
|
|
113
|
-
|
|
114
|
-
test('parseFrontmatter() returns both data and content', (t) => {
|
|
115
|
-
const content = `---
|
|
116
|
-
title: Test Topic
|
|
117
|
-
description: A description
|
|
118
|
-
---
|
|
119
|
-
# Heading
|
|
120
|
-
|
|
121
|
-
Body content.`
|
|
122
|
-
|
|
123
|
-
const result = parseFrontmatter(content)
|
|
124
|
-
|
|
125
|
-
t.deepEqual(result.data, {
|
|
126
|
-
title: 'Test Topic',
|
|
127
|
-
description: 'A description'
|
|
128
|
-
})
|
|
129
|
-
t.is(result.content, '# Heading\n\nBody content.')
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
test('parseFrontmatter() returns empty data when no frontmatter', (t) => {
|
|
133
|
-
const content = '# Just Content'
|
|
134
|
-
|
|
135
|
-
const result = parseFrontmatter(content)
|
|
136
|
-
|
|
137
|
-
t.deepEqual(result.data, {})
|
|
138
|
-
t.is(result.content, '# Just Content')
|
|
139
|
-
})
|