@atcute/lex-cli 2.5.2 → 2.6.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.
- package/dist/codegen.d.ts +1 -7
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +20 -42
- package/dist/codegen.js.map +1 -1
- package/dist/commands/export.d.ts +2 -6
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +5 -17
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/generate.d.ts +2 -6
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +12 -10
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/pull.d.ts +2 -6
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +12 -17
- package/dist/commands/pull.js.map +1 -1
- package/dist/config.d.ts +17 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +21 -3
- package/dist/config.js.map +1 -1
- package/dist/formatter.d.ts +19 -0
- package/dist/formatter.d.ts.map +1 -0
- package/dist/formatter.js +111 -0
- package/dist/formatter.js.map +1 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts +2 -66
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lexicon-loader.d.ts.map +1 -1
- package/dist/lexicon-loader.js +9 -1
- package/dist/lexicon-loader.js.map +1 -1
- package/dist/lexicon-metadata.d.ts.map +1 -1
- package/dist/lexicon-metadata.js +1 -1
- package/dist/lexicon-metadata.js.map +1 -1
- package/dist/pull-sources/atproto.d.ts +3 -11
- package/dist/pull-sources/atproto.d.ts.map +1 -1
- package/dist/pull-sources/atproto.js.map +1 -1
- package/dist/pull-sources/git.d.ts +3 -7
- package/dist/pull-sources/git.d.ts.map +1 -1
- package/dist/pull-sources/git.js.map +1 -1
- package/dist/shared-options.d.ts +1 -1
- package/package.json +18 -15
- package/src/cli.ts +3 -3
- package/src/codegen.ts +47 -72
- package/src/commands/export.ts +9 -20
- package/src/commands/generate.ts +21 -17
- package/src/commands/pull.ts +18 -23
- package/src/config.ts +19 -4
- package/src/formatter.ts +145 -0
- package/src/index.ts +1 -1
- package/src/lexicon-metadata.ts +2 -2
- package/src/pull-sources/atproto.ts +4 -2
- package/src/pull-sources/git.ts +5 -3
package/src/formatter.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { availableParallelism } from 'node:os';
|
|
3
|
+
|
|
4
|
+
import type { FormatterConfig } from './config.ts';
|
|
5
|
+
|
|
6
|
+
/** formats source code */
|
|
7
|
+
export interface Formatter {
|
|
8
|
+
/**
|
|
9
|
+
* formats the given code
|
|
10
|
+
* @param code source code to format
|
|
11
|
+
* @param filepath filepath hint for language detection and config resolution
|
|
12
|
+
* @returns formatted code
|
|
13
|
+
*/
|
|
14
|
+
format(code: string, filepath: string): Promise<string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const inferPrettierParser = (filepath: string): string => {
|
|
18
|
+
if (filepath.endsWith('.ts') || filepath.endsWith('.tsx')) {
|
|
19
|
+
return 'typescript';
|
|
20
|
+
}
|
|
21
|
+
if (filepath.endsWith('.json')) {
|
|
22
|
+
return 'json';
|
|
23
|
+
}
|
|
24
|
+
if (filepath.endsWith('.md') || filepath.endsWith('.markdown')) {
|
|
25
|
+
return 'markdown';
|
|
26
|
+
}
|
|
27
|
+
return 'typescript';
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// #region semaphore
|
|
31
|
+
|
|
32
|
+
interface Lock {
|
|
33
|
+
release(): void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class Semaphore {
|
|
37
|
+
private waiting: (() => void)[] = [];
|
|
38
|
+
private active = 0;
|
|
39
|
+
private max: number;
|
|
40
|
+
|
|
41
|
+
constructor(max: number) {
|
|
42
|
+
this.max = max;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
acquire(): Promise<Lock> {
|
|
46
|
+
const lock: Lock = {
|
|
47
|
+
release: () => {
|
|
48
|
+
this.active--;
|
|
49
|
+
const next = this.waiting.shift();
|
|
50
|
+
if (next) {
|
|
51
|
+
this.active++;
|
|
52
|
+
next();
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
if (this.active < this.max) {
|
|
58
|
+
this.active++;
|
|
59
|
+
return Promise.resolve(lock);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const { promise, resolve } = Promise.withResolvers<Lock>();
|
|
63
|
+
this.waiting.push(() => resolve(lock));
|
|
64
|
+
return promise;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// #endregion
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* creates a formatter from the given configuration
|
|
72
|
+
* @param config formatter configuration
|
|
73
|
+
* @param root project root for config resolution
|
|
74
|
+
* @returns a formatter instance
|
|
75
|
+
*/
|
|
76
|
+
export const createFormatter = async (config: FormatterConfig, root: string): Promise<Formatter> => {
|
|
77
|
+
let inner: Formatter;
|
|
78
|
+
let concurrency: number;
|
|
79
|
+
|
|
80
|
+
if (config.type === 'prettier') {
|
|
81
|
+
const prettier = await import('prettier');
|
|
82
|
+
const prettierConfig = await prettier.resolveConfig(root, { editorconfig: true });
|
|
83
|
+
|
|
84
|
+
// prettier is in-process and CPU-bound, so concurrency only helps
|
|
85
|
+
// avoid buffering all files in memory at once
|
|
86
|
+
concurrency = availableParallelism();
|
|
87
|
+
inner = {
|
|
88
|
+
async format(code, filepath) {
|
|
89
|
+
return prettier.format(code, { ...prettierConfig, parser: inferPrettierParser(filepath) });
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
} else {
|
|
93
|
+
// the template uses {filepath} as a placeholder, which is passed as a
|
|
94
|
+
// positional argument to sh to avoid shell injection via filenames
|
|
95
|
+
const shellCmd = config.command.replaceAll('{filepath}', '"$1"');
|
|
96
|
+
|
|
97
|
+
concurrency = config.concurrency;
|
|
98
|
+
inner = {
|
|
99
|
+
format(code, filepath) {
|
|
100
|
+
return new Promise<string>((resolve, reject) => {
|
|
101
|
+
const child = spawn('sh', ['-c', shellCmd, 'sh', filepath], {
|
|
102
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const stdoutChunks: Buffer[] = [];
|
|
106
|
+
const stderrChunks: Buffer[] = [];
|
|
107
|
+
|
|
108
|
+
child.stdout.on('data', (chunk: Buffer) => {
|
|
109
|
+
stdoutChunks.push(chunk);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
child.stderr.on('data', (chunk: Buffer) => {
|
|
113
|
+
stderrChunks.push(chunk);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
child.on('error', reject);
|
|
117
|
+
|
|
118
|
+
child.on('close', (exitCode: number | null) => {
|
|
119
|
+
if (exitCode !== 0) {
|
|
120
|
+
const stderr = Buffer.concat(stderrChunks).toString();
|
|
121
|
+
reject(new Error(`formatter exited with code ${exitCode}:\n${stderr}`));
|
|
122
|
+
} else {
|
|
123
|
+
resolve(Buffer.concat(stdoutChunks).toString());
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
child.stdin.end(code);
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const semaphore = new Semaphore(concurrency);
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
async format(code, filepath) {
|
|
137
|
+
const lock = await semaphore.acquire();
|
|
138
|
+
try {
|
|
139
|
+
return await inner.format(code, filepath);
|
|
140
|
+
} finally {
|
|
141
|
+
lock.release();
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
};
|
package/src/index.ts
CHANGED
package/src/lexicon-metadata.ts
CHANGED
|
@@ -17,10 +17,12 @@ import {
|
|
|
17
17
|
type AtprotoDid,
|
|
18
18
|
type Nsid,
|
|
19
19
|
} from '@atcute/lexicons/syntax';
|
|
20
|
+
|
|
20
21
|
import pc from 'picocolors';
|
|
21
22
|
|
|
22
|
-
import type { AtprotoSourceConfig } from '../config.
|
|
23
|
-
|
|
23
|
+
import type { AtprotoSourceConfig } from '../config.ts';
|
|
24
|
+
|
|
25
|
+
import type { PullResult, SourceLocation } from './types.ts';
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* discovers all published lexicons for an authority by listing records in the
|
package/src/pull-sources/git.ts
CHANGED
|
@@ -3,11 +3,13 @@ import * as os from 'node:os';
|
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
|
|
5
5
|
import type { LexiconDoc } from '@atcute/lexicon-doc';
|
|
6
|
+
|
|
6
7
|
import pc from 'picocolors';
|
|
7
8
|
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
|
|
9
|
+
import type { GitSourceConfig } from '../config.ts';
|
|
10
|
+
import { runGit, GitError } from '../git.ts';
|
|
11
|
+
|
|
12
|
+
import type { PullResult, PulledLexicon, SourceLocation } from './types.ts';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* pulls lexicon documents from a git repository source
|