docrev 0.8.1 → 0.8.5
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/.claude/settings.local.json +9 -0
- package/PLAN-tables-and-postprocess.md +850 -0
- package/README.md +33 -0
- package/bin/rev.js +12 -131
- package/bin/rev.ts +145 -0
- package/dist/bin/rev.d.ts +9 -0
- package/dist/bin/rev.d.ts.map +1 -0
- package/dist/bin/rev.js +118 -0
- package/dist/bin/rev.js.map +1 -0
- package/dist/lib/annotations.d.ts +91 -0
- package/dist/lib/annotations.d.ts.map +1 -0
- package/dist/lib/annotations.js +554 -0
- package/dist/lib/annotations.js.map +1 -0
- package/dist/lib/build.d.ts +171 -0
- package/dist/lib/build.d.ts.map +1 -0
- package/dist/lib/build.js +755 -0
- package/dist/lib/build.js.map +1 -0
- package/dist/lib/citations.d.ts +34 -0
- package/dist/lib/citations.d.ts.map +1 -0
- package/dist/lib/citations.js +140 -0
- package/dist/lib/citations.js.map +1 -0
- package/dist/lib/commands/build.d.ts +13 -0
- package/dist/lib/commands/build.d.ts.map +1 -0
- package/dist/lib/commands/build.js +678 -0
- package/dist/lib/commands/build.js.map +1 -0
- package/dist/lib/commands/citations.d.ts +11 -0
- package/dist/lib/commands/citations.d.ts.map +1 -0
- package/dist/lib/commands/citations.js +428 -0
- package/dist/lib/commands/citations.js.map +1 -0
- package/dist/lib/commands/comments.d.ts +11 -0
- package/dist/lib/commands/comments.d.ts.map +1 -0
- package/dist/lib/commands/comments.js +883 -0
- package/dist/lib/commands/comments.js.map +1 -0
- package/dist/lib/commands/context.d.ts +35 -0
- package/dist/lib/commands/context.d.ts.map +1 -0
- package/dist/lib/commands/context.js +59 -0
- package/dist/lib/commands/context.js.map +1 -0
- package/dist/lib/commands/core.d.ts +11 -0
- package/dist/lib/commands/core.d.ts.map +1 -0
- package/dist/lib/commands/core.js +246 -0
- package/dist/lib/commands/core.js.map +1 -0
- package/dist/lib/commands/doi.d.ts +11 -0
- package/dist/lib/commands/doi.d.ts.map +1 -0
- package/dist/lib/commands/doi.js +373 -0
- package/dist/lib/commands/doi.js.map +1 -0
- package/dist/lib/commands/history.d.ts +11 -0
- package/dist/lib/commands/history.d.ts.map +1 -0
- package/dist/lib/commands/history.js +245 -0
- package/dist/lib/commands/history.js.map +1 -0
- package/dist/lib/commands/index.d.ts +28 -0
- package/dist/lib/commands/index.d.ts.map +1 -0
- package/dist/lib/commands/index.js +35 -0
- package/dist/lib/commands/index.js.map +1 -0
- package/dist/lib/commands/init.d.ts +11 -0
- package/dist/lib/commands/init.d.ts.map +1 -0
- package/dist/lib/commands/init.js +209 -0
- package/dist/lib/commands/init.js.map +1 -0
- package/dist/lib/commands/response.d.ts +11 -0
- package/dist/lib/commands/response.d.ts.map +1 -0
- package/dist/lib/commands/response.js +317 -0
- package/dist/lib/commands/response.js.map +1 -0
- package/dist/lib/commands/sections.d.ts +11 -0
- package/dist/lib/commands/sections.d.ts.map +1 -0
- package/dist/lib/commands/sections.js +1071 -0
- package/dist/lib/commands/sections.js.map +1 -0
- package/dist/lib/commands/utilities.d.ts +19 -0
- package/dist/lib/commands/utilities.d.ts.map +1 -0
- package/dist/lib/commands/utilities.js +2009 -0
- package/dist/lib/commands/utilities.js.map +1 -0
- package/dist/lib/comment-realign.d.ts +50 -0
- package/dist/lib/comment-realign.d.ts.map +1 -0
- package/dist/lib/comment-realign.js +372 -0
- package/dist/lib/comment-realign.js.map +1 -0
- package/dist/lib/config.d.ts +41 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +76 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/crossref.d.ts +108 -0
- package/dist/lib/crossref.d.ts.map +1 -0
- package/dist/lib/crossref.js +597 -0
- package/dist/lib/crossref.js.map +1 -0
- package/dist/lib/dependencies.d.ts +30 -0
- package/dist/lib/dependencies.d.ts.map +1 -0
- package/dist/lib/dependencies.js +95 -0
- package/dist/lib/dependencies.js.map +1 -0
- package/dist/lib/doi-cache.d.ts +29 -0
- package/dist/lib/doi-cache.d.ts.map +1 -0
- package/dist/lib/doi-cache.js +104 -0
- package/dist/lib/doi-cache.js.map +1 -0
- package/dist/lib/doi.d.ts +65 -0
- package/dist/lib/doi.d.ts.map +1 -0
- package/dist/lib/doi.js +710 -0
- package/dist/lib/doi.js.map +1 -0
- package/dist/lib/equations.d.ts +61 -0
- package/dist/lib/equations.d.ts.map +1 -0
- package/dist/lib/equations.js +445 -0
- package/dist/lib/equations.js.map +1 -0
- package/dist/lib/errors.d.ts +60 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +303 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/format.d.ts +104 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +416 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/git.d.ts +88 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +304 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/grammar.d.ts +62 -0
- package/dist/lib/grammar.d.ts.map +1 -0
- package/dist/lib/grammar.js +244 -0
- package/dist/lib/grammar.js.map +1 -0
- package/dist/lib/image-registry.d.ts +68 -0
- package/dist/lib/image-registry.d.ts.map +1 -0
- package/dist/lib/image-registry.js +112 -0
- package/dist/lib/image-registry.js.map +1 -0
- package/dist/lib/import.d.ts +184 -0
- package/dist/lib/import.d.ts.map +1 -0
- package/dist/lib/import.js +1581 -0
- package/dist/lib/import.js.map +1 -0
- package/dist/lib/journals.d.ts +55 -0
- package/dist/lib/journals.d.ts.map +1 -0
- package/dist/lib/journals.js +417 -0
- package/dist/lib/journals.js.map +1 -0
- package/dist/lib/merge.d.ts +138 -0
- package/dist/lib/merge.d.ts.map +1 -0
- package/dist/lib/merge.js +603 -0
- package/dist/lib/merge.js.map +1 -0
- package/dist/lib/orcid.d.ts +36 -0
- package/dist/lib/orcid.d.ts.map +1 -0
- package/dist/lib/orcid.js +117 -0
- package/dist/lib/orcid.js.map +1 -0
- package/dist/lib/pdf-comments.d.ts +95 -0
- package/dist/lib/pdf-comments.d.ts.map +1 -0
- package/dist/lib/pdf-comments.js +192 -0
- package/dist/lib/pdf-comments.js.map +1 -0
- package/dist/lib/pdf-import.d.ts +118 -0
- package/dist/lib/pdf-import.d.ts.map +1 -0
- package/dist/lib/pdf-import.js +397 -0
- package/dist/lib/pdf-import.js.map +1 -0
- package/dist/lib/plugins.d.ts +76 -0
- package/dist/lib/plugins.d.ts.map +1 -0
- package/dist/lib/plugins.js +235 -0
- package/dist/lib/plugins.js.map +1 -0
- package/dist/lib/postprocess.d.ts +42 -0
- package/dist/lib/postprocess.d.ts.map +1 -0
- package/dist/lib/postprocess.js +138 -0
- package/dist/lib/postprocess.js.map +1 -0
- package/dist/lib/pptx-template.d.ts +59 -0
- package/dist/lib/pptx-template.d.ts.map +1 -0
- package/dist/lib/pptx-template.js +613 -0
- package/dist/lib/pptx-template.js.map +1 -0
- package/dist/lib/pptx-themes.d.ts +80 -0
- package/dist/lib/pptx-themes.d.ts.map +1 -0
- package/dist/lib/pptx-themes.js +818 -0
- package/dist/lib/pptx-themes.js.map +1 -0
- package/dist/lib/protect-restore.d.ts +137 -0
- package/dist/lib/protect-restore.d.ts.map +1 -0
- package/dist/lib/protect-restore.js +394 -0
- package/dist/lib/protect-restore.js.map +1 -0
- package/dist/lib/rate-limiter.d.ts +27 -0
- package/dist/lib/rate-limiter.d.ts.map +1 -0
- package/dist/lib/rate-limiter.js +79 -0
- package/dist/lib/rate-limiter.js.map +1 -0
- package/dist/lib/response.d.ts +41 -0
- package/dist/lib/response.d.ts.map +1 -0
- package/dist/lib/response.js +150 -0
- package/dist/lib/response.js.map +1 -0
- package/dist/lib/review.d.ts +35 -0
- package/dist/lib/review.d.ts.map +1 -0
- package/dist/lib/review.js +263 -0
- package/dist/lib/review.js.map +1 -0
- package/dist/lib/schema.d.ts +66 -0
- package/dist/lib/schema.d.ts.map +1 -0
- package/dist/lib/schema.js +339 -0
- package/dist/lib/schema.js.map +1 -0
- package/dist/lib/scientific-words.d.ts +6 -0
- package/dist/lib/scientific-words.d.ts.map +1 -0
- package/dist/lib/scientific-words.js +66 -0
- package/dist/lib/scientific-words.js.map +1 -0
- package/dist/lib/sections.d.ts +40 -0
- package/dist/lib/sections.d.ts.map +1 -0
- package/dist/lib/sections.js +288 -0
- package/dist/lib/sections.js.map +1 -0
- package/dist/lib/slides.d.ts +86 -0
- package/dist/lib/slides.d.ts.map +1 -0
- package/dist/lib/slides.js +676 -0
- package/dist/lib/slides.js.map +1 -0
- package/dist/lib/spelling.d.ts +76 -0
- package/dist/lib/spelling.d.ts.map +1 -0
- package/dist/lib/spelling.js +272 -0
- package/dist/lib/spelling.js.map +1 -0
- package/dist/lib/templates.d.ts +30 -0
- package/dist/lib/templates.d.ts.map +1 -0
- package/dist/lib/templates.js +504 -0
- package/dist/lib/templates.js.map +1 -0
- package/dist/lib/themes.d.ts +85 -0
- package/dist/lib/themes.d.ts.map +1 -0
- package/dist/lib/themes.js +652 -0
- package/dist/lib/themes.js.map +1 -0
- package/dist/lib/trackchanges.d.ts +51 -0
- package/dist/lib/trackchanges.d.ts.map +1 -0
- package/dist/lib/trackchanges.js +202 -0
- package/dist/lib/trackchanges.js.map +1 -0
- package/dist/lib/tui.d.ts +76 -0
- package/dist/lib/tui.d.ts.map +1 -0
- package/dist/lib/tui.js +377 -0
- package/dist/lib/tui.js.map +1 -0
- package/dist/lib/types.d.ts +447 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +6 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/undo.d.ts +57 -0
- package/dist/lib/undo.d.ts.map +1 -0
- package/dist/lib/undo.js +185 -0
- package/dist/lib/undo.js.map +1 -0
- package/dist/lib/utils.d.ts +16 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +40 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/variables.d.ts +42 -0
- package/dist/lib/variables.d.ts.map +1 -0
- package/dist/lib/variables.js +141 -0
- package/dist/lib/variables.js.map +1 -0
- package/dist/lib/word.d.ts +80 -0
- package/dist/lib/word.d.ts.map +1 -0
- package/dist/lib/word.js +360 -0
- package/dist/lib/word.js.map +1 -0
- package/dist/lib/wordcomments.d.ts +51 -0
- package/dist/lib/wordcomments.d.ts.map +1 -0
- package/dist/lib/wordcomments.js +587 -0
- package/dist/lib/wordcomments.js.map +1 -0
- package/eslint.config.js +27 -0
- package/lib/annotations.ts +622 -0
- package/lib/apply-buildup-colors.py +88 -0
- package/lib/build.ts +1013 -0
- package/lib/{citations.js → citations.ts} +38 -27
- package/lib/commands/{build.js → build.ts} +80 -27
- package/lib/commands/{citations.js → citations.ts} +36 -18
- package/lib/commands/{comments.js → comments.ts} +187 -54
- package/lib/commands/{context.js → context.ts} +18 -8
- package/lib/commands/{core.js → core.ts} +34 -20
- package/lib/commands/{doi.js → doi.ts} +32 -16
- package/lib/commands/{history.js → history.ts} +25 -12
- package/lib/commands/{index.js → index.ts} +9 -5
- package/lib/commands/{init.js → init.ts} +20 -8
- package/lib/commands/{response.js → response.ts} +47 -20
- package/lib/commands/{sections.js → sections.ts} +273 -68
- package/lib/commands/{utilities.js → utilities.ts} +338 -158
- package/lib/{comment-realign.js → comment-realign.ts} +117 -45
- package/lib/config.ts +84 -0
- package/lib/{crossref.js → crossref.ts} +213 -138
- package/lib/dependencies.ts +106 -0
- package/lib/doi-cache.ts +115 -0
- package/lib/{doi.js → doi.ts} +115 -281
- package/lib/{equations.js → equations.ts} +60 -64
- package/lib/{errors.js → errors.ts} +56 -48
- package/lib/{format.js → format.ts} +137 -63
- package/lib/{git.js → git.ts} +66 -63
- package/lib/{grammar.js → grammar.ts} +45 -32
- package/lib/image-registry.ts +180 -0
- package/lib/import.ts +2060 -0
- package/lib/journals.ts +505 -0
- package/lib/{merge.js → merge.ts} +185 -135
- package/lib/{orcid.js → orcid.ts} +17 -22
- package/lib/{pdf-comments.js → pdf-comments.ts} +76 -18
- package/lib/{pdf-import.js → pdf-import.ts} +148 -70
- package/lib/{plugins.js → plugins.ts} +82 -39
- package/lib/postprocess.ts +188 -0
- package/lib/pptx-color-filter.lua +37 -0
- package/lib/pptx-template.ts +625 -0
- package/lib/pptx-themes/academic.pptx +0 -0
- package/lib/pptx-themes/corporate.pptx +0 -0
- package/lib/pptx-themes/dark.pptx +0 -0
- package/lib/pptx-themes/default.pptx +0 -0
- package/lib/pptx-themes/minimal.pptx +0 -0
- package/lib/pptx-themes/plant.pptx +0 -0
- package/lib/pptx-themes.ts +896 -0
- package/lib/protect-restore.ts +516 -0
- package/lib/rate-limiter.ts +94 -0
- package/lib/{response.js → response.ts} +36 -21
- package/lib/{review.js → review.ts} +53 -43
- package/lib/{schema.js → schema.ts} +70 -25
- package/lib/{sections.js → sections.ts} +71 -76
- package/lib/slides.ts +793 -0
- package/lib/{spelling.js → spelling.ts} +43 -59
- package/lib/{templates.js → templates.ts} +20 -17
- package/lib/themes.ts +742 -0
- package/lib/{trackchanges.js → trackchanges.ts} +52 -23
- package/lib/types.ts +509 -0
- package/lib/{undo.js → undo.ts} +75 -52
- package/lib/utils.ts +41 -0
- package/lib/{variables.js → variables.ts} +60 -54
- package/lib/word.ts +428 -0
- package/lib/{wordcomments.js → wordcomments.ts} +94 -40
- package/package.json +15 -5
- package/skill/REFERENCE.md +67 -0
- package/tsconfig.json +26 -0
- package/lib/annotations.js +0 -414
- package/lib/build.js +0 -639
- package/lib/config.js +0 -79
- package/lib/import.js +0 -1145
- package/lib/journals.js +0 -629
- package/lib/word.js +0 -225
- /package/lib/{scientific-words.js → scientific-words.ts} +0 -0
package/lib/build.js
DELETED
|
@@ -1,639 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build system - combines sections → paper.md → PDF/DOCX/TEX
|
|
3
|
-
*
|
|
4
|
-
* Features:
|
|
5
|
-
* - Reads rev.yaml config
|
|
6
|
-
* - Combines section files into paper.md (persisted)
|
|
7
|
-
* - Strips annotations appropriately per output format
|
|
8
|
-
* - Runs pandoc with crossref filter
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import * as fs from 'fs';
|
|
12
|
-
import * as path from 'path';
|
|
13
|
-
import { execSync, spawn } from 'child_process';
|
|
14
|
-
import YAML from 'yaml';
|
|
15
|
-
import { stripAnnotations } from './annotations.js';
|
|
16
|
-
import { buildRegistry, labelToDisplay, detectDynamicRefs, resolveForwardRefs } from './crossref.js';
|
|
17
|
-
import { processVariables, hasVariables } from './variables.js';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Default rev.yaml configuration
|
|
21
|
-
*/
|
|
22
|
-
export const DEFAULT_CONFIG = {
|
|
23
|
-
title: 'Untitled Document',
|
|
24
|
-
authors: [],
|
|
25
|
-
sections: [],
|
|
26
|
-
bibliography: null,
|
|
27
|
-
csl: null,
|
|
28
|
-
crossref: {
|
|
29
|
-
figureTitle: 'Figure',
|
|
30
|
-
tableTitle: 'Table',
|
|
31
|
-
figPrefix: ['Fig.', 'Figs.'],
|
|
32
|
-
tblPrefix: ['Table', 'Tables'],
|
|
33
|
-
secPrefix: ['Section', 'Sections'],
|
|
34
|
-
linkReferences: true,
|
|
35
|
-
},
|
|
36
|
-
pdf: {
|
|
37
|
-
template: null,
|
|
38
|
-
documentclass: 'article',
|
|
39
|
-
fontsize: '12pt',
|
|
40
|
-
geometry: 'margin=1in',
|
|
41
|
-
linestretch: 1.5,
|
|
42
|
-
numbersections: false,
|
|
43
|
-
toc: false,
|
|
44
|
-
},
|
|
45
|
-
docx: {
|
|
46
|
-
reference: null,
|
|
47
|
-
keepComments: true,
|
|
48
|
-
toc: false,
|
|
49
|
-
},
|
|
50
|
-
tex: {
|
|
51
|
-
standalone: true,
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Load rev.yaml config from directory
|
|
57
|
-
* @param {string} directory
|
|
58
|
-
* @returns {object} merged config with defaults
|
|
59
|
-
*/
|
|
60
|
-
export function loadConfig(directory) {
|
|
61
|
-
const configPath = path.join(directory, 'rev.yaml');
|
|
62
|
-
|
|
63
|
-
if (!fs.existsSync(configPath)) {
|
|
64
|
-
return { ...DEFAULT_CONFIG, _configPath: null };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
69
|
-
const userConfig = YAML.parse(content) || {};
|
|
70
|
-
|
|
71
|
-
// Deep merge with defaults
|
|
72
|
-
const config = {
|
|
73
|
-
...DEFAULT_CONFIG,
|
|
74
|
-
...userConfig,
|
|
75
|
-
crossref: { ...DEFAULT_CONFIG.crossref, ...userConfig.crossref },
|
|
76
|
-
pdf: { ...DEFAULT_CONFIG.pdf, ...userConfig.pdf },
|
|
77
|
-
docx: { ...DEFAULT_CONFIG.docx, ...userConfig.docx },
|
|
78
|
-
tex: { ...DEFAULT_CONFIG.tex, ...userConfig.tex },
|
|
79
|
-
_configPath: configPath,
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return config;
|
|
83
|
-
} catch (err) {
|
|
84
|
-
throw new Error(`Failed to parse rev.yaml: ${err.message}`);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Find section files in directory
|
|
90
|
-
* @param {string} directory
|
|
91
|
-
* @param {string[]} configSections - sections from rev.yaml (optional)
|
|
92
|
-
* @returns {string[]} ordered list of section files
|
|
93
|
-
*/
|
|
94
|
-
export function findSections(directory, configSections = []) {
|
|
95
|
-
// If sections specified in config, use that order
|
|
96
|
-
if (configSections.length > 0) {
|
|
97
|
-
const sections = [];
|
|
98
|
-
for (const section of configSections) {
|
|
99
|
-
const filePath = path.join(directory, section);
|
|
100
|
-
if (fs.existsSync(filePath)) {
|
|
101
|
-
sections.push(section);
|
|
102
|
-
} else {
|
|
103
|
-
console.warn(`Warning: Section file not found: ${section}`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return sections;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Try sections.yaml
|
|
110
|
-
const sectionsYamlPath = path.join(directory, 'sections.yaml');
|
|
111
|
-
if (fs.existsSync(sectionsYamlPath)) {
|
|
112
|
-
try {
|
|
113
|
-
const sectionsConfig = YAML.parse(fs.readFileSync(sectionsYamlPath, 'utf-8'));
|
|
114
|
-
if (sectionsConfig.sections) {
|
|
115
|
-
return Object.entries(sectionsConfig.sections)
|
|
116
|
-
.sort((a, b) => (a[1].order ?? 999) - (b[1].order ?? 999))
|
|
117
|
-
.map(([file]) => file)
|
|
118
|
-
.filter((f) => fs.existsSync(path.join(directory, f)));
|
|
119
|
-
}
|
|
120
|
-
} catch {
|
|
121
|
-
// Ignore yaml errors
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Default: find all .md files except special ones
|
|
126
|
-
const exclude = ['paper.md', 'readme.md', 'claude.md'];
|
|
127
|
-
const files = fs.readdirSync(directory).filter((f) => {
|
|
128
|
-
if (!f.endsWith('.md')) return false;
|
|
129
|
-
if (exclude.includes(f.toLowerCase())) return false;
|
|
130
|
-
return true;
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Sort alphabetically as fallback
|
|
134
|
-
return files.sort();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Combine section files into paper.md
|
|
139
|
-
* @param {string} directory
|
|
140
|
-
* @param {object} config
|
|
141
|
-
* @param {object} options
|
|
142
|
-
* @returns {string} path to paper.md
|
|
143
|
-
*/
|
|
144
|
-
export function combineSections(directory, config, options = {}) {
|
|
145
|
-
const sections = findSections(directory, config.sections);
|
|
146
|
-
|
|
147
|
-
if (sections.length === 0) {
|
|
148
|
-
throw new Error('No section files found. Create .md files or specify sections in rev.yaml');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const parts = [];
|
|
152
|
-
|
|
153
|
-
// Add YAML frontmatter
|
|
154
|
-
const frontmatter = buildFrontmatter(config);
|
|
155
|
-
parts.push('---');
|
|
156
|
-
parts.push(YAML.stringify(frontmatter).trim());
|
|
157
|
-
parts.push('---');
|
|
158
|
-
parts.push('');
|
|
159
|
-
|
|
160
|
-
// Read all section contents for variable processing
|
|
161
|
-
const sectionContents = [];
|
|
162
|
-
|
|
163
|
-
// Check if we need to auto-inject references before supplementary
|
|
164
|
-
// Pandoc places refs at the end by default, which breaks when supplementary follows
|
|
165
|
-
const hasRefsSection = sections.some(s =>
|
|
166
|
-
s.toLowerCase().includes('reference') || s.toLowerCase().includes('refs')
|
|
167
|
-
);
|
|
168
|
-
const suppIndex = sections.findIndex(s =>
|
|
169
|
-
s.toLowerCase().includes('supp') || s.toLowerCase().includes('appendix')
|
|
170
|
-
);
|
|
171
|
-
const hasBibliography = config.bibliography && fs.existsSync(path.join(directory, config.bibliography));
|
|
172
|
-
|
|
173
|
-
// Track if we find an explicit refs div in any section
|
|
174
|
-
let hasExplicitRefsDiv = false;
|
|
175
|
-
|
|
176
|
-
// Combine sections
|
|
177
|
-
for (let i = 0; i < sections.length; i++) {
|
|
178
|
-
const section = sections[i];
|
|
179
|
-
const filePath = path.join(directory, section);
|
|
180
|
-
let content = fs.readFileSync(filePath, 'utf-8');
|
|
181
|
-
|
|
182
|
-
// Remove any existing frontmatter from section files
|
|
183
|
-
content = stripFrontmatter(content);
|
|
184
|
-
sectionContents.push(content);
|
|
185
|
-
|
|
186
|
-
// Check if this section has an explicit refs div
|
|
187
|
-
if (content.includes('::: {#refs}') || content.includes('::: {#refs}')) {
|
|
188
|
-
hasExplicitRefsDiv = true;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Auto-inject references before supplementary if needed
|
|
192
|
-
if (i === suppIndex && hasBibliography && !hasRefsSection && !hasExplicitRefsDiv) {
|
|
193
|
-
parts.push('# References\n');
|
|
194
|
-
parts.push('::: {#refs}');
|
|
195
|
-
parts.push(':::');
|
|
196
|
-
parts.push('');
|
|
197
|
-
parts.push('');
|
|
198
|
-
options._refsAutoInjected = true;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
parts.push(content.trim());
|
|
202
|
-
parts.push('');
|
|
203
|
-
parts.push(''); // Double newline between sections
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
let paperContent = parts.join('\n');
|
|
207
|
-
|
|
208
|
-
// Process template variables if any exist
|
|
209
|
-
if (hasVariables(paperContent)) {
|
|
210
|
-
paperContent = processVariables(paperContent, config, { sectionContents });
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Resolve forward references (refs that appear before their anchor definition)
|
|
214
|
-
// This fixes pandoc-crossref limitation with multi-file documents
|
|
215
|
-
if (hasPandocCrossref()) {
|
|
216
|
-
const registry = buildRegistry(directory, sections);
|
|
217
|
-
const { text, resolved } = resolveForwardRefs(paperContent, registry);
|
|
218
|
-
if (resolved.length > 0) {
|
|
219
|
-
paperContent = text;
|
|
220
|
-
// Store resolved count for optional reporting
|
|
221
|
-
options._forwardRefsResolved = resolved.length;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const paperPath = path.join(directory, 'paper.md');
|
|
226
|
-
|
|
227
|
-
fs.writeFileSync(paperPath, paperContent, 'utf-8');
|
|
228
|
-
|
|
229
|
-
return paperPath;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Build YAML frontmatter from config
|
|
234
|
-
* @param {object} config
|
|
235
|
-
* @returns {object}
|
|
236
|
-
*/
|
|
237
|
-
function buildFrontmatter(config) {
|
|
238
|
-
const fm = {};
|
|
239
|
-
|
|
240
|
-
if (config.title) fm.title = config.title;
|
|
241
|
-
|
|
242
|
-
if (config.authors && config.authors.length > 0) {
|
|
243
|
-
fm.author = config.authors;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (config.bibliography) {
|
|
247
|
-
fm.bibliography = config.bibliography;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (config.csl) {
|
|
251
|
-
fm.csl = config.csl;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return fm;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Strip YAML frontmatter from content
|
|
259
|
-
* @param {string} content
|
|
260
|
-
* @returns {string}
|
|
261
|
-
*/
|
|
262
|
-
function stripFrontmatter(content) {
|
|
263
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
|
|
264
|
-
if (match) {
|
|
265
|
-
return content.slice(match[0].length);
|
|
266
|
-
}
|
|
267
|
-
return content;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Prepare paper.md for specific output format
|
|
272
|
-
* @param {string} paperPath
|
|
273
|
-
* @param {string} format - 'pdf', 'docx', 'tex'
|
|
274
|
-
* @param {object} config
|
|
275
|
-
* @param {object} options
|
|
276
|
-
* @returns {string} path to prepared file
|
|
277
|
-
*/
|
|
278
|
-
export function prepareForFormat(paperPath, format, config, options = {}) {
|
|
279
|
-
const directory = path.dirname(paperPath);
|
|
280
|
-
let content = fs.readFileSync(paperPath, 'utf-8');
|
|
281
|
-
|
|
282
|
-
// Build crossref registry for reference conversion
|
|
283
|
-
// Pass sections from config to ensure correct file ordering
|
|
284
|
-
const registry = buildRegistry(directory, config.sections);
|
|
285
|
-
|
|
286
|
-
if (format === 'pdf' || format === 'tex') {
|
|
287
|
-
// Strip all annotations for clean output
|
|
288
|
-
content = stripAnnotations(content);
|
|
289
|
-
} else if (format === 'docx') {
|
|
290
|
-
// Strip track changes, optionally keep comments
|
|
291
|
-
content = stripAnnotations(content, { keepComments: config.docx.keepComments });
|
|
292
|
-
|
|
293
|
-
// Convert @fig:label to "Figure 1" for Word readers
|
|
294
|
-
content = convertDynamicRefsToDisplay(content, registry);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Write to temporary file
|
|
298
|
-
const preparedPath = path.join(directory, `.paper-${format}.md`);
|
|
299
|
-
fs.writeFileSync(preparedPath, content, 'utf-8');
|
|
300
|
-
|
|
301
|
-
return preparedPath;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Convert @fig:label references to display format (Figure 1)
|
|
306
|
-
* @param {string} text
|
|
307
|
-
* @param {object} registry
|
|
308
|
-
* @returns {string}
|
|
309
|
-
*/
|
|
310
|
-
function convertDynamicRefsToDisplay(text, registry) {
|
|
311
|
-
const refs = detectDynamicRefs(text);
|
|
312
|
-
|
|
313
|
-
// Process in reverse order to preserve positions
|
|
314
|
-
let result = text;
|
|
315
|
-
for (let i = refs.length - 1; i >= 0; i--) {
|
|
316
|
-
const ref = refs[i];
|
|
317
|
-
const display = labelToDisplay(ref.type, ref.label, registry);
|
|
318
|
-
|
|
319
|
-
if (display) {
|
|
320
|
-
result = result.slice(0, ref.position) + display + result.slice(ref.position + ref.match.length);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
return result;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Build pandoc arguments for format
|
|
329
|
-
* @param {string} format
|
|
330
|
-
* @param {object} config
|
|
331
|
-
* @param {string} outputPath
|
|
332
|
-
* @returns {string[]}
|
|
333
|
-
*/
|
|
334
|
-
export function buildPandocArgs(format, config, outputPath) {
|
|
335
|
-
const args = [];
|
|
336
|
-
|
|
337
|
-
// Output format
|
|
338
|
-
if (format === 'tex') {
|
|
339
|
-
args.push('-t', 'latex');
|
|
340
|
-
if (config.tex.standalone) {
|
|
341
|
-
args.push('-s');
|
|
342
|
-
}
|
|
343
|
-
} else if (format === 'pdf') {
|
|
344
|
-
args.push('-t', 'pdf');
|
|
345
|
-
} else if (format === 'docx') {
|
|
346
|
-
args.push('-t', 'docx');
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
args.push('-o', outputPath);
|
|
350
|
-
|
|
351
|
-
// Crossref filter (if available)
|
|
352
|
-
if (hasPandocCrossref()) {
|
|
353
|
-
args.push('--filter', 'pandoc-crossref');
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Bibliography
|
|
357
|
-
if (config.bibliography) {
|
|
358
|
-
args.push('--citeproc');
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Format-specific options
|
|
362
|
-
if (format === 'pdf') {
|
|
363
|
-
if (config.pdf.template) {
|
|
364
|
-
args.push('--template', config.pdf.template);
|
|
365
|
-
}
|
|
366
|
-
args.push('-V', `documentclass=${config.pdf.documentclass}`);
|
|
367
|
-
args.push('-V', `fontsize=${config.pdf.fontsize}`);
|
|
368
|
-
args.push('-V', `geometry:${config.pdf.geometry}`);
|
|
369
|
-
if (config.pdf.linestretch !== 1) {
|
|
370
|
-
args.push('-V', `linestretch=${config.pdf.linestretch}`);
|
|
371
|
-
}
|
|
372
|
-
if (config.pdf.numbersections) {
|
|
373
|
-
args.push('--number-sections');
|
|
374
|
-
}
|
|
375
|
-
if (config.pdf.toc) {
|
|
376
|
-
args.push('--toc');
|
|
377
|
-
}
|
|
378
|
-
} else if (format === 'docx') {
|
|
379
|
-
if (config.docx.reference) {
|
|
380
|
-
args.push('--reference-doc', config.docx.reference);
|
|
381
|
-
}
|
|
382
|
-
if (config.docx.toc) {
|
|
383
|
-
args.push('--toc');
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
return args;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Check if pandoc-crossref is available
|
|
392
|
-
* @returns {boolean}
|
|
393
|
-
*/
|
|
394
|
-
export function hasPandocCrossref() {
|
|
395
|
-
try {
|
|
396
|
-
execSync('pandoc-crossref --version', { stdio: 'ignore' });
|
|
397
|
-
return true;
|
|
398
|
-
} catch {
|
|
399
|
-
return false;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Check if pandoc is available
|
|
405
|
-
* @returns {boolean}
|
|
406
|
-
*/
|
|
407
|
-
export function hasPandoc() {
|
|
408
|
-
try {
|
|
409
|
-
execSync('pandoc --version', { stdio: 'ignore' });
|
|
410
|
-
return true;
|
|
411
|
-
} catch {
|
|
412
|
-
return false;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
* Check if LaTeX is available (for PDF generation)
|
|
418
|
-
* @returns {boolean}
|
|
419
|
-
*/
|
|
420
|
-
export function hasLatex() {
|
|
421
|
-
try {
|
|
422
|
-
execSync('pdflatex --version', { stdio: 'ignore' });
|
|
423
|
-
return true;
|
|
424
|
-
} catch {
|
|
425
|
-
try {
|
|
426
|
-
execSync('xelatex --version', { stdio: 'ignore' });
|
|
427
|
-
return true;
|
|
428
|
-
} catch {
|
|
429
|
-
return false;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Get installation instructions for missing dependencies
|
|
436
|
-
* @param {string} dependency - 'pandoc', 'latex', 'pandoc-crossref'
|
|
437
|
-
* @returns {string}
|
|
438
|
-
*/
|
|
439
|
-
export function getInstallInstructions(dependency) {
|
|
440
|
-
const platform = process.platform;
|
|
441
|
-
const instructions = {
|
|
442
|
-
pandoc: {
|
|
443
|
-
darwin: 'brew install pandoc',
|
|
444
|
-
win32: 'winget install JohnMacFarlane.Pandoc',
|
|
445
|
-
linux: 'sudo apt install pandoc',
|
|
446
|
-
},
|
|
447
|
-
latex: {
|
|
448
|
-
darwin: 'brew install --cask mactex-no-gui',
|
|
449
|
-
win32: 'Install MiKTeX from https://miktex.org/download',
|
|
450
|
-
linux: 'sudo apt install texlive-latex-base texlive-fonts-recommended',
|
|
451
|
-
},
|
|
452
|
-
'pandoc-crossref': {
|
|
453
|
-
darwin: 'brew install pandoc-crossref',
|
|
454
|
-
win32: 'Download from https://github.com/lierdakil/pandoc-crossref/releases',
|
|
455
|
-
linux: 'Download from https://github.com/lierdakil/pandoc-crossref/releases',
|
|
456
|
-
},
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
const platformInstructions = instructions[dependency];
|
|
460
|
-
if (!platformInstructions) return '';
|
|
461
|
-
|
|
462
|
-
return platformInstructions[platform] || platformInstructions.linux;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* Check dependencies and return status
|
|
467
|
-
* @returns {{ pandoc: boolean, latex: boolean, crossref: boolean, messages: string[] }}
|
|
468
|
-
*/
|
|
469
|
-
export function checkDependencies() {
|
|
470
|
-
const status = {
|
|
471
|
-
pandoc: hasPandoc(),
|
|
472
|
-
latex: hasLatex(),
|
|
473
|
-
crossref: hasPandocCrossref(),
|
|
474
|
-
messages: [],
|
|
475
|
-
};
|
|
476
|
-
|
|
477
|
-
if (!status.pandoc) {
|
|
478
|
-
status.messages.push(`Pandoc not found. Install with: ${getInstallInstructions('pandoc')}`);
|
|
479
|
-
}
|
|
480
|
-
if (!status.latex) {
|
|
481
|
-
status.messages.push(`LaTeX not found (required for PDF). Install with: ${getInstallInstructions('latex')}`);
|
|
482
|
-
}
|
|
483
|
-
if (!status.crossref) {
|
|
484
|
-
status.messages.push(`pandoc-crossref not found (optional, for figure/table refs). Install with: ${getInstallInstructions('pandoc-crossref')}`);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
return status;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Write crossref.yaml if needed
|
|
492
|
-
* @param {string} directory
|
|
493
|
-
* @param {object} config
|
|
494
|
-
*/
|
|
495
|
-
function ensureCrossrefConfig(directory, config) {
|
|
496
|
-
const crossrefPath = path.join(directory, 'crossref.yaml');
|
|
497
|
-
|
|
498
|
-
if (!fs.existsSync(crossrefPath) && hasPandocCrossref()) {
|
|
499
|
-
fs.writeFileSync(crossrefPath, YAML.stringify(config.crossref), 'utf-8');
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Run pandoc build
|
|
505
|
-
* @param {string} inputPath
|
|
506
|
-
* @param {string} format
|
|
507
|
-
* @param {object} config
|
|
508
|
-
* @param {object} options
|
|
509
|
-
* @returns {Promise<{outputPath: string, success: boolean, error?: string}>}
|
|
510
|
-
*/
|
|
511
|
-
export async function runPandoc(inputPath, format, config, options = {}) {
|
|
512
|
-
const directory = path.dirname(inputPath);
|
|
513
|
-
const baseName = config.title
|
|
514
|
-
? config.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 50)
|
|
515
|
-
: 'paper';
|
|
516
|
-
|
|
517
|
-
const ext = format === 'tex' ? '.tex' : format === 'pdf' ? '.pdf' : '.docx';
|
|
518
|
-
// Allow custom output path via options
|
|
519
|
-
const outputPath = options.outputPath || path.join(directory, `${baseName}${ext}`);
|
|
520
|
-
|
|
521
|
-
// Ensure crossref.yaml exists
|
|
522
|
-
ensureCrossrefConfig(directory, config);
|
|
523
|
-
|
|
524
|
-
const args = buildPandocArgs(format, config, outputPath);
|
|
525
|
-
|
|
526
|
-
// Add crossref metadata file if exists
|
|
527
|
-
const crossrefPath = path.join(directory, 'crossref.yaml');
|
|
528
|
-
if (fs.existsSync(crossrefPath) && hasPandocCrossref()) {
|
|
529
|
-
args.push('--metadata-file', crossrefPath);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Input file
|
|
533
|
-
args.push(inputPath);
|
|
534
|
-
|
|
535
|
-
return new Promise((resolve) => {
|
|
536
|
-
const pandoc = spawn('pandoc', args, {
|
|
537
|
-
cwd: directory,
|
|
538
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
let stderr = '';
|
|
542
|
-
pandoc.stderr.on('data', (data) => {
|
|
543
|
-
stderr += data.toString();
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
pandoc.on('close', (code) => {
|
|
547
|
-
if (code === 0) {
|
|
548
|
-
resolve({ outputPath, success: true });
|
|
549
|
-
} else {
|
|
550
|
-
resolve({ outputPath, success: false, error: stderr || `Exit code ${code}` });
|
|
551
|
-
}
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
pandoc.on('error', (err) => {
|
|
555
|
-
resolve({ outputPath, success: false, error: err.message });
|
|
556
|
-
});
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
/**
|
|
561
|
-
* Full build pipeline
|
|
562
|
-
* @param {string} directory
|
|
563
|
-
* @param {string[]} formats - ['pdf', 'docx', 'tex'] or ['all']
|
|
564
|
-
* @param {object} options
|
|
565
|
-
* @returns {Promise<{results: object[], paperPath: string, warnings: string[], forwardRefsResolved: number}>}
|
|
566
|
-
*/
|
|
567
|
-
export async function build(directory, formats = ['pdf', 'docx'], options = {}) {
|
|
568
|
-
const warnings = [];
|
|
569
|
-
let forwardRefsResolved = 0;
|
|
570
|
-
|
|
571
|
-
// Check pandoc
|
|
572
|
-
if (!hasPandoc()) {
|
|
573
|
-
const instruction = getInstallInstructions('pandoc');
|
|
574
|
-
throw new Error(`Pandoc not found. Install with: ${instruction}\nOr run: rev doctor`);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// Check LaTeX if PDF is requested
|
|
578
|
-
if ((formats.includes('pdf') || formats.includes('all')) && !hasLatex()) {
|
|
579
|
-
warnings.push(`LaTeX not found - PDF generation may fail. Install with: ${getInstallInstructions('latex')}`);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Check pandoc-crossref
|
|
583
|
-
if (!hasPandocCrossref()) {
|
|
584
|
-
warnings.push('pandoc-crossref not found - figure/table numbering will not work');
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// Load config (use passed config if provided, otherwise load from file)
|
|
588
|
-
const config = options.config || loadConfig(directory);
|
|
589
|
-
|
|
590
|
-
// Combine sections → paper.md
|
|
591
|
-
const buildOptions = { ...options };
|
|
592
|
-
const paperPath = combineSections(directory, config, buildOptions);
|
|
593
|
-
forwardRefsResolved = buildOptions._forwardRefsResolved || 0;
|
|
594
|
-
const refsAutoInjected = buildOptions._refsAutoInjected || false;
|
|
595
|
-
|
|
596
|
-
// Expand 'all' to all formats
|
|
597
|
-
if (formats.includes('all')) {
|
|
598
|
-
formats = ['pdf', 'docx', 'tex'];
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
const results = [];
|
|
602
|
-
|
|
603
|
-
for (const format of formats) {
|
|
604
|
-
// Prepare format-specific version
|
|
605
|
-
const preparedPath = prepareForFormat(paperPath, format, config, options);
|
|
606
|
-
|
|
607
|
-
// Run pandoc
|
|
608
|
-
const result = await runPandoc(preparedPath, format, config, options);
|
|
609
|
-
results.push({ format, ...result });
|
|
610
|
-
|
|
611
|
-
// Clean up temp file
|
|
612
|
-
try {
|
|
613
|
-
fs.unlinkSync(preparedPath);
|
|
614
|
-
} catch {
|
|
615
|
-
// Ignore cleanup errors
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
return { results, paperPath, warnings, forwardRefsResolved, refsAutoInjected };
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
/**
|
|
623
|
-
* Get build status summary
|
|
624
|
-
* @param {object[]} results
|
|
625
|
-
* @returns {string}
|
|
626
|
-
*/
|
|
627
|
-
export function formatBuildResults(results) {
|
|
628
|
-
const lines = [];
|
|
629
|
-
|
|
630
|
-
for (const r of results) {
|
|
631
|
-
if (r.success) {
|
|
632
|
-
lines.push(` ${r.format.toUpperCase()}: ${path.basename(r.outputPath)}`);
|
|
633
|
-
} else {
|
|
634
|
-
lines.push(` ${r.format.toUpperCase()}: FAILED - ${r.error}`);
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
return lines.join('\n');
|
|
639
|
-
}
|
package/lib/config.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User configuration management
|
|
3
|
-
* Stores user preferences in ~/.revrc
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as fs from 'fs';
|
|
7
|
-
import * as path from 'path';
|
|
8
|
-
import * as os from 'os';
|
|
9
|
-
|
|
10
|
-
const CONFIG_PATH = path.join(os.homedir(), '.revrc');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Load user config
|
|
14
|
-
* @returns {object}
|
|
15
|
-
*/
|
|
16
|
-
export function loadUserConfig() {
|
|
17
|
-
try {
|
|
18
|
-
if (fs.existsSync(CONFIG_PATH)) {
|
|
19
|
-
return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
20
|
-
}
|
|
21
|
-
} catch {
|
|
22
|
-
// Ignore parse errors
|
|
23
|
-
}
|
|
24
|
-
return {};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Save user config
|
|
29
|
-
* @param {object} config
|
|
30
|
-
*/
|
|
31
|
-
export function saveUserConfig(config) {
|
|
32
|
-
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Get user name
|
|
37
|
-
* @returns {string|null}
|
|
38
|
-
*/
|
|
39
|
-
export function getUserName() {
|
|
40
|
-
const config = loadUserConfig();
|
|
41
|
-
return config.userName || null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Set user name
|
|
46
|
-
* @param {string} name
|
|
47
|
-
*/
|
|
48
|
-
export function setUserName(name) {
|
|
49
|
-
const config = loadUserConfig();
|
|
50
|
-
config.userName = name;
|
|
51
|
-
saveUserConfig(config);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Get config file path
|
|
56
|
-
* @returns {string}
|
|
57
|
-
*/
|
|
58
|
-
export function getConfigPath() {
|
|
59
|
-
return CONFIG_PATH;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Get default sections for new projects
|
|
64
|
-
* @returns {string[]|null}
|
|
65
|
-
*/
|
|
66
|
-
export function getDefaultSections() {
|
|
67
|
-
const config = loadUserConfig();
|
|
68
|
-
return config.defaultSections || null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Set default sections for new projects
|
|
73
|
-
* @param {string[]} sections - Array of section names (without .md extension)
|
|
74
|
-
*/
|
|
75
|
-
export function setDefaultSections(sections) {
|
|
76
|
-
const config = loadUserConfig();
|
|
77
|
-
config.defaultSections = sections;
|
|
78
|
-
saveUserConfig(config);
|
|
79
|
-
}
|