@aloth/olcli 0.1.8 → 0.3.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.
@@ -0,0 +1,85 @@
1
+ /**
2
+ * olcli ignore subsystem
3
+ *
4
+ * Layered defense against syncing local LaTeX build artifacts (and other
5
+ * unwanted files) up to Overleaf:
6
+ *
7
+ * 1. Built-in ignore list — always on, opt out with --no-default-ignore
8
+ * 2. .olignore — project-level, gitignore-style syntax
9
+ * 3. .olignore.local — machine-specific, never synced (gitignore'd)
10
+ *
11
+ * Special PDF rule: ignore `X.pdf` only if a same-named `X.tex` (or `.ltx`)
12
+ * exists in the same folder. This kills `thesis.pdf` next to `thesis.tex`
13
+ * but preserves a hand-uploaded `figures/diagram.pdf`.
14
+ *
15
+ * Escape hatches:
16
+ * --no-default-ignore → only .olignore + .olignore.local apply
17
+ * --no-ignore → no filtering at all
18
+ *
19
+ * See issue #19 for design rationale.
20
+ */
21
+ import { Ignore } from 'ignore';
22
+ /**
23
+ * Default ignore patterns, applied unless --no-default-ignore is set.
24
+ *
25
+ * Covers LaTeX build artifacts (pdflatex / xelatex / lualatex / latexmk /
26
+ * biber / makeindex / glossaries / minted), common editor noise, and
27
+ * conventional build directories.
28
+ *
29
+ * Note: `*.pdf` is NOT in this list — see shouldIgnore() for the special
30
+ * sibling-`.tex` rule.
31
+ */
32
+ export declare const DEFAULT_IGNORE_PATTERNS: readonly string[];
33
+ /**
34
+ * Resolved ignore configuration for a project directory.
35
+ */
36
+ export interface IgnoreContext {
37
+ /** All effective patterns in priority order (later overrides earlier). */
38
+ patterns: string[];
39
+ /** Sources contributing to `patterns`, for `olcli ignored` output. */
40
+ sources: Array<{
41
+ label: string;
42
+ patterns: string[];
43
+ }>;
44
+ /** True when defaults are enabled. */
45
+ defaultsEnabled: boolean;
46
+ /** True when ignore filtering is enabled at all. */
47
+ enabled: boolean;
48
+ /** Compiled matcher; null when `enabled === false`. */
49
+ matcher: Ignore | null;
50
+ }
51
+ export interface LoadIgnoreOptions {
52
+ /** Disable the built-in DEFAULT_IGNORE_PATTERNS list. */
53
+ noDefaults?: boolean;
54
+ /** Disable all ignore filtering entirely (overrides everything else). */
55
+ disableAll?: boolean;
56
+ }
57
+ /**
58
+ * Build an IgnoreContext for the given project root.
59
+ *
60
+ * Layering (lowest → highest precedence; `ignore` semantics: later wins):
61
+ * 1. DEFAULT_IGNORE_PATTERNS (unless noDefaults)
62
+ * 2. <root>/.olignore (project, version-controlled)
63
+ * 3. <root>/.olignore.local (machine-only, gitignore'd)
64
+ */
65
+ export declare function loadIgnore(root: string, opts?: LoadIgnoreOptions): IgnoreContext;
66
+ /**
67
+ * Decide whether a given relative path should be ignored.
68
+ *
69
+ * @param relativePath Path relative to the project root, forward-slash.
70
+ * For directories, callers may pass `dir/` (trailing
71
+ * slash) to engage gitignore directory matching.
72
+ * @param ctx From `loadIgnore`.
73
+ * @param siblingTexBaseNames Set of file basenames (without extension) in
74
+ * the same folder as `relativePath` that have a `.tex`
75
+ * or `.ltx` source. Used for the PDF special rule.
76
+ * Pass `undefined` to skip the PDF rule.
77
+ */
78
+ export declare function shouldIgnore(relativePath: string, ctx: IgnoreContext, siblingTexBaseNames?: Set<string>): boolean;
79
+ /**
80
+ * Convenience: build a per-folder set of basenames that have a `.tex` or
81
+ * `.ltx` companion. Caller passes the list of files in that folder (just
82
+ * basenames, not full paths).
83
+ */
84
+ export declare function buildTexSiblingSet(folderFileNames: Iterable<string>): Set<string>;
85
+ //# sourceMappingURL=ignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignore.d.ts","sourceRoot":"","sources":["../src/ignore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAe,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EA6BnD,CAAC;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,sEAAsE;IACtE,OAAO,EAAE,KAAK,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC,CAAC;IACH,sCAAsC;IACtC,eAAe,EAAE,OAAO,CAAC;IACzB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAmBD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,iBAAsB,GAAG,aAAa,CAwCpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,aAAa,EAClB,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAChC,OAAO,CAuBT;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAOjF"}
package/dist/ignore.js ADDED
@@ -0,0 +1,172 @@
1
+ /**
2
+ * olcli ignore subsystem
3
+ *
4
+ * Layered defense against syncing local LaTeX build artifacts (and other
5
+ * unwanted files) up to Overleaf:
6
+ *
7
+ * 1. Built-in ignore list — always on, opt out with --no-default-ignore
8
+ * 2. .olignore — project-level, gitignore-style syntax
9
+ * 3. .olignore.local — machine-specific, never synced (gitignore'd)
10
+ *
11
+ * Special PDF rule: ignore `X.pdf` only if a same-named `X.tex` (or `.ltx`)
12
+ * exists in the same folder. This kills `thesis.pdf` next to `thesis.tex`
13
+ * but preserves a hand-uploaded `figures/diagram.pdf`.
14
+ *
15
+ * Escape hatches:
16
+ * --no-default-ignore → only .olignore + .olignore.local apply
17
+ * --no-ignore → no filtering at all
18
+ *
19
+ * See issue #19 for design rationale.
20
+ */
21
+ import { readFileSync, existsSync } from 'node:fs';
22
+ import { join, basename } from 'node:path';
23
+ import ignore from 'ignore';
24
+ /**
25
+ * Default ignore patterns, applied unless --no-default-ignore is set.
26
+ *
27
+ * Covers LaTeX build artifacts (pdflatex / xelatex / lualatex / latexmk /
28
+ * biber / makeindex / glossaries / minted), common editor noise, and
29
+ * conventional build directories.
30
+ *
31
+ * Note: `*.pdf` is NOT in this list — see shouldIgnore() for the special
32
+ * sibling-`.tex` rule.
33
+ */
34
+ export const DEFAULT_IGNORE_PATTERNS = Object.freeze([
35
+ // ─── LaTeX core build artifacts ───────────────────────────────────────
36
+ '*.aux', '*.bbl', '*.blg', '*.log', '*.out', '*.toc',
37
+ '*.lof', '*.lot',
38
+ // latexmk
39
+ '*.fls', '*.fdb_latexmk',
40
+ // synctex
41
+ '*.synctex.gz', '*.synctex',
42
+ // Beamer
43
+ '*.nav', '*.snm', '*.vrb',
44
+ // makeindex
45
+ '*.idx', '*.ind', '*.ilg',
46
+ // glossaries
47
+ '*.glo', '*.gls', '*.glg', '*.acn', '*.acr', '*.alg',
48
+ '*.ist', '*.xdy',
49
+ // biber / biblatex
50
+ '*.bcf', '*.run.xml',
51
+ // xelatex / dvi
52
+ '*.xdv', '*.dvi',
53
+ // pdflatex aux variants
54
+ '*.pyg', // minted pygments cache leftover
55
+ // ─── Build directories ────────────────────────────────────────────────
56
+ '_minted-*/',
57
+ 'build/', 'out/', 'dist/',
58
+ // ─── Editor / OS noise ────────────────────────────────────────────────
59
+ '.DS_Store', 'Thumbs.db', 'desktop.ini',
60
+ '*.swp', '*.swo', '*~', '*.bak',
61
+ // ─── Overleaf-specific reserved ───────────────────────────────────────
62
+ 'output.pdf', // Overleaf compile output convention
63
+ ]);
64
+ /**
65
+ * Read patterns from a .olignore-style file. Returns [] if missing.
66
+ * Comments (# …) and blank lines are stripped by the `ignore` package
67
+ * itself; we just split on newlines.
68
+ */
69
+ function readIgnoreFile(path) {
70
+ if (!existsSync(path))
71
+ return [];
72
+ try {
73
+ return readFileSync(path, 'utf-8')
74
+ .split(/\r?\n/)
75
+ .map((line) => line.replace(/\s+$/, ''))
76
+ .filter((line) => line.length > 0 && !line.startsWith('#'));
77
+ }
78
+ catch {
79
+ return [];
80
+ }
81
+ }
82
+ /**
83
+ * Build an IgnoreContext for the given project root.
84
+ *
85
+ * Layering (lowest → highest precedence; `ignore` semantics: later wins):
86
+ * 1. DEFAULT_IGNORE_PATTERNS (unless noDefaults)
87
+ * 2. <root>/.olignore (project, version-controlled)
88
+ * 3. <root>/.olignore.local (machine-only, gitignore'd)
89
+ */
90
+ export function loadIgnore(root, opts = {}) {
91
+ if (opts.disableAll) {
92
+ return {
93
+ patterns: [],
94
+ sources: [],
95
+ defaultsEnabled: false,
96
+ enabled: false,
97
+ matcher: null,
98
+ };
99
+ }
100
+ const sources = [];
101
+ if (!opts.noDefaults) {
102
+ sources.push({
103
+ label: 'built-in defaults',
104
+ patterns: [...DEFAULT_IGNORE_PATTERNS],
105
+ });
106
+ }
107
+ const projectIgnore = readIgnoreFile(join(root, '.olignore'));
108
+ if (projectIgnore.length > 0) {
109
+ sources.push({ label: '.olignore', patterns: projectIgnore });
110
+ }
111
+ const localIgnore = readIgnoreFile(join(root, '.olignore.local'));
112
+ if (localIgnore.length > 0) {
113
+ sources.push({ label: '.olignore.local', patterns: localIgnore });
114
+ }
115
+ const patterns = sources.flatMap((s) => s.patterns);
116
+ const matcher = ignore().add(patterns);
117
+ return {
118
+ patterns,
119
+ sources,
120
+ defaultsEnabled: !opts.noDefaults,
121
+ enabled: true,
122
+ matcher,
123
+ };
124
+ }
125
+ /**
126
+ * Decide whether a given relative path should be ignored.
127
+ *
128
+ * @param relativePath Path relative to the project root, forward-slash.
129
+ * For directories, callers may pass `dir/` (trailing
130
+ * slash) to engage gitignore directory matching.
131
+ * @param ctx From `loadIgnore`.
132
+ * @param siblingTexBaseNames Set of file basenames (without extension) in
133
+ * the same folder as `relativePath` that have a `.tex`
134
+ * or `.ltx` source. Used for the PDF special rule.
135
+ * Pass `undefined` to skip the PDF rule.
136
+ */
137
+ export function shouldIgnore(relativePath, ctx, siblingTexBaseNames) {
138
+ if (!ctx.enabled || !ctx.matcher)
139
+ return false;
140
+ // The `ignore` package requires forward slashes and rejects leading `/`.
141
+ const normalized = relativePath.replace(/\\/g, '/').replace(/^\/+/, '');
142
+ if (normalized === '' || normalized === '.')
143
+ return false;
144
+ if (ctx.matcher.ignores(normalized))
145
+ return true;
146
+ // Special PDF rule (only when defaults active — it's a default-list policy):
147
+ // ignore `X.pdf` if a sibling `X.tex` (or .ltx) exists.
148
+ if (ctx.defaultsEnabled &&
149
+ siblingTexBaseNames &&
150
+ /\.pdf$/i.test(normalized)) {
151
+ const base = basename(normalized).replace(/\.pdf$/i, '');
152
+ if (siblingTexBaseNames.has(base.toLowerCase())) {
153
+ return true;
154
+ }
155
+ }
156
+ return false;
157
+ }
158
+ /**
159
+ * Convenience: build a per-folder set of basenames that have a `.tex` or
160
+ * `.ltx` companion. Caller passes the list of files in that folder (just
161
+ * basenames, not full paths).
162
+ */
163
+ export function buildTexSiblingSet(folderFileNames) {
164
+ const out = new Set();
165
+ for (const name of folderFileNames) {
166
+ const m = name.match(/^(.+)\.(tex|ltx)$/i);
167
+ if (m)
168
+ out.add(m[1].toLowerCase());
169
+ }
170
+ return out;
171
+ }
172
+ //# sourceMappingURL=ignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignore.js","sourceRoot":"","sources":["../src/ignore.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aloth/olcli",
3
- "version": "0.1.8",
3
+ "version": "0.3.0",
4
4
  "description": "Command-line interface for Overleaf — Sync, manage, and compile LaTeX projects from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -49,6 +49,7 @@
49
49
  "cheerio": "^1.0.0",
50
50
  "commander": "^12.1.0",
51
51
  "conf": "^13.0.0",
52
+ "ignore": "^7.0.5",
52
53
  "ora": "^8.0.1",
53
54
  "tough-cookie": "^4.1.4"
54
55
  },