@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.
Files changed (54) hide show
  1. package/dist/codegen.d.ts +1 -7
  2. package/dist/codegen.d.ts.map +1 -1
  3. package/dist/codegen.js +20 -42
  4. package/dist/codegen.js.map +1 -1
  5. package/dist/commands/export.d.ts +2 -6
  6. package/dist/commands/export.d.ts.map +1 -1
  7. package/dist/commands/export.js +5 -17
  8. package/dist/commands/export.js.map +1 -1
  9. package/dist/commands/generate.d.ts +2 -6
  10. package/dist/commands/generate.d.ts.map +1 -1
  11. package/dist/commands/generate.js +12 -10
  12. package/dist/commands/generate.js.map +1 -1
  13. package/dist/commands/pull.d.ts +2 -6
  14. package/dist/commands/pull.d.ts.map +1 -1
  15. package/dist/commands/pull.js +12 -17
  16. package/dist/commands/pull.js.map +1 -1
  17. package/dist/config.d.ts +17 -2
  18. package/dist/config.d.ts.map +1 -1
  19. package/dist/config.js +21 -3
  20. package/dist/config.js.map +1 -1
  21. package/dist/formatter.d.ts +19 -0
  22. package/dist/formatter.d.ts.map +1 -0
  23. package/dist/formatter.js +111 -0
  24. package/dist/formatter.js.map +1 -0
  25. package/dist/git.d.ts.map +1 -1
  26. package/dist/git.js.map +1 -1
  27. package/dist/index.d.ts +2 -66
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/lexicon-loader.d.ts.map +1 -1
  31. package/dist/lexicon-loader.js +9 -1
  32. package/dist/lexicon-loader.js.map +1 -1
  33. package/dist/lexicon-metadata.d.ts.map +1 -1
  34. package/dist/lexicon-metadata.js +1 -1
  35. package/dist/lexicon-metadata.js.map +1 -1
  36. package/dist/pull-sources/atproto.d.ts +3 -11
  37. package/dist/pull-sources/atproto.d.ts.map +1 -1
  38. package/dist/pull-sources/atproto.js.map +1 -1
  39. package/dist/pull-sources/git.d.ts +3 -7
  40. package/dist/pull-sources/git.d.ts.map +1 -1
  41. package/dist/pull-sources/git.js.map +1 -1
  42. package/dist/shared-options.d.ts +1 -1
  43. package/package.json +18 -15
  44. package/src/cli.ts +3 -3
  45. package/src/codegen.ts +47 -72
  46. package/src/commands/export.ts +9 -20
  47. package/src/commands/generate.ts +21 -17
  48. package/src/commands/pull.ts +18 -23
  49. package/src/config.ts +19 -4
  50. package/src/formatter.ts +145 -0
  51. package/src/index.ts +1 -1
  52. package/src/lexicon-metadata.ts +2 -2
  53. package/src/pull-sources/atproto.ts +4 -2
  54. package/src/pull-sources/git.ts +5 -3
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/pull-sources/git.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/pull-sources/git.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export declare const sharedOptions: import("@optique/core/parser").Parser<{
1
+ export declare const sharedOptions: import("@optique/core/parser").Parser<"sync", {
2
2
  readonly config: string | undefined;
3
3
  }, {
4
4
  readonly config: [import("@optique/core/valueparser").ValueParserResult<string> | undefined] | undefined;
package/package.json CHANGED
@@ -1,39 +1,42 @@
1
1
  {
2
- "type": "module",
3
2
  "name": "@atcute/lex-cli",
4
- "version": "2.5.2",
3
+ "version": "2.6.0",
5
4
  "description": "cli tool to generate type definitions for atcute",
6
5
  "license": "0BSD",
7
6
  "repository": {
8
7
  "url": "https://github.com/mary-ext/atcute",
9
8
  "directory": "packages/lexicons/lex-cli"
10
9
  },
10
+ "bin": "./cli.mjs",
11
11
  "files": [
12
+ "cli.mjs",
12
13
  "dist/",
14
+ "schema/",
13
15
  "src/",
14
16
  "!src/**/*.bench.ts",
15
- "!src/**/*.test.ts",
16
- "cli.mjs",
17
- "schema/"
17
+ "!src/**/*.test.ts"
18
18
  ],
19
- "bin": "./cli.mjs",
19
+ "type": "module",
20
20
  "exports": {
21
21
  ".": "./dist/index.js"
22
22
  },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
23
26
  "dependencies": {
24
27
  "@badrap/valita": "^0.4.6",
25
- "@optique/core": "^0.6.3",
26
- "@optique/run": "^0.6.3",
28
+ "@optique/core": "^0.10.7",
29
+ "@optique/run": "^0.10.7",
27
30
  "picocolors": "^1.1.1",
28
- "prettier": "^3.7.1",
29
- "@atcute/identity": "^1.1.3",
30
- "@atcute/identity-resolver": "^1.2.0",
31
- "@atcute/lexicon-resolver": "^0.1.5",
32
- "@atcute/lexicon-doc": "^2.0.5",
33
- "@atcute/lexicons": "^1.2.5"
31
+ "prettier": "^3.8.1",
32
+ "@atcute/identity": "^1.1.4",
33
+ "@atcute/identity-resolver": "^1.2.2",
34
+ "@atcute/lexicon-doc": "^2.1.2",
35
+ "@atcute/lexicon-resolver": "^0.1.6",
36
+ "@atcute/lexicons": "^1.2.9"
34
37
  },
35
38
  "devDependencies": {
36
- "@types/node": "^22.19.1",
39
+ "@types/node": "^25.5.2",
37
40
  "tschema": "^3.2.0"
38
41
  },
39
42
  "scripts": {
package/src/cli.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { or } from '@optique/core/constructs';
2
2
  import { run } from '@optique/run';
3
3
 
4
- import { exportCommandSchema, runExport } from './commands/export.js';
5
- import { generateCommandSchema, runGenerate } from './commands/generate.js';
6
- import { pullCommandSchema, runPull } from './commands/pull.js';
4
+ import { exportCommandSchema, runExport } from './commands/export.ts';
5
+ import { generateCommandSchema, runGenerate } from './commands/generate.ts';
6
+ import { pullCommandSchema, runPull } from './commands/pull.ts';
7
7
 
8
8
  const parser = or(generateCommandSchema, pullCommandSchema, exportCommandSchema);
9
9
 
package/src/codegen.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import { dirname as getDirname, relative as getRelativePath } from 'node:path/posix';
2
2
 
3
- import * as prettier from 'prettier';
4
-
5
3
  import type {
6
4
  LexDefinableField,
7
5
  LexiconDoc,
@@ -16,6 +14,7 @@ import type {
16
14
  LexXrpcQuery,
17
15
  LexXrpcSubscription,
18
16
  } from '@atcute/lexicon-doc';
17
+ import { formatLexiconRef, parseLexiconRef, type ParsedLexiconRef } from '@atcute/lexicon-doc';
19
18
 
20
19
  export interface SourceFile {
21
20
  filename: string;
@@ -33,13 +32,6 @@ export interface LexiconApiOptions {
33
32
  modules: {
34
33
  importSuffix: string;
35
34
  };
36
- prettier: {
37
- cwd: string;
38
- };
39
- }
40
-
41
- export interface LexiconApiResult {
42
- files: SourceFile[];
43
35
  }
44
36
 
45
37
  type DocumentMap = Map<string, LexiconDoc>;
@@ -49,31 +41,8 @@ type Literal = string | number | boolean;
49
41
 
50
42
  const lit: (val: Literal | Literal[]) => string = JSON.stringify;
51
43
 
52
- interface LexPath {
53
- nsid: string;
54
- defId: string;
55
- }
56
-
57
- const toLexUri = (path: LexPath): string => {
58
- const { nsid, defId } = path;
59
- return defId === 'main' ? nsid : `${nsid}#${defId}`;
60
- };
61
-
62
- const resolvePath = (from: LexPath, ref: string): LexPath => {
63
- const index = ref.indexOf('#');
64
-
65
- // nsid (no hash)
66
- if (index === -1) {
67
- return { nsid: ref, defId: 'main' };
68
- }
69
-
70
- // #defId (local ref)
71
- if (index === 0) {
72
- return { nsid: from.nsid, defId: ref.slice(1) };
73
- }
74
-
75
- // nsid#defId (full ref)
76
- return { nsid: ref.slice(0, index), defId: ref.slice(index + 1) };
44
+ const resolvePath = (from: ParsedLexiconRef, ref: string): ParsedLexiconRef => {
45
+ return parseLexiconRef(ref, from.nsid);
77
46
  };
78
47
 
79
48
  const resolveExternalImport = (nsid: string, mappings: ImportMapping[]): ImportMapping | undefined => {
@@ -90,7 +59,7 @@ const resolveExternalImport = (nsid: string, mappings: ImportMapping[]): ImportM
90
59
 
91
60
  const PURE = `/*#__PURE__*/`;
92
61
 
93
- export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<LexiconApiResult> => {
62
+ export function* generateLexiconApi(opts: LexiconApiOptions): Generator<SourceFile> {
94
63
  const importExt = opts.modules?.importSuffix;
95
64
 
96
65
  const documents = opts.documents.toSorted((a, b) => {
@@ -105,7 +74,6 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
105
74
  });
106
75
 
107
76
  const map: DocumentMap = new Map(documents.map((doc) => [doc.id, doc]));
108
- const files: SourceFile[] = [];
109
77
  const generatedIds = new Set<string>();
110
78
 
111
79
  for (const doc of documents) {
@@ -139,7 +107,7 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
139
107
 
140
108
  for (const defId of sortedDefIds) {
141
109
  const def = doc.defs[defId];
142
- const path: LexPath = { nsid: doc.id, defId };
110
+ const path: ParsedLexiconRef = { nsid: doc.id, defId };
143
111
 
144
112
  const camelcased = toCamelCase(defId);
145
113
  const varname = `${camelcased}Schema`;
@@ -153,7 +121,7 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
153
121
 
154
122
  file.ambients += `declare module '@atcute/lexicons/ambient' {\n`;
155
123
  file.ambients += ` interface XRPCQueries {\n`;
156
- file.ambients += ` ${lit(toLexUri(path))}: ${camelcased}Schema;\n`;
124
+ file.ambients += ` ${lit(formatLexiconRef(path))}: ${camelcased}Schema;\n`;
157
125
  file.ambients += ` }\n`;
158
126
  file.ambients += `}`;
159
127
  break;
@@ -165,7 +133,7 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
165
133
 
166
134
  file.ambients += `declare module '@atcute/lexicons/ambient' {\n`;
167
135
  file.ambients += ` interface XRPCProcedures {\n`;
168
- file.ambients += ` ${lit(toLexUri(path))}: ${camelcased}Schema;\n`;
136
+ file.ambients += ` ${lit(formatLexiconRef(path))}: ${camelcased}Schema;\n`;
169
137
  file.ambients += ` }\n`;
170
138
  file.ambients += `}`;
171
139
  break;
@@ -177,7 +145,7 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
177
145
 
178
146
  file.ambients += `declare module '@atcute/lexicons/ambient' {\n`;
179
147
  file.ambients += ` interface XRPCSubscriptions {\n`;
180
- file.ambients += ` ${lit(toLexUri(path))}: ${camelcased}Schema;\n`;
148
+ file.ambients += ` ${lit(formatLexiconRef(path))}: ${camelcased}Schema;\n`;
181
149
  file.ambients += ` }\n`;
182
150
  file.ambients += `}`;
183
151
  break;
@@ -193,13 +161,13 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
193
161
 
194
162
  file.ambients += `declare module '@atcute/lexicons/ambient' {\n`;
195
163
  file.ambients += ` interface Records {\n`;
196
- file.ambients += ` ${lit(toLexUri(path))}: ${camelcased}Schema;\n`;
164
+ file.ambients += ` ${lit(formatLexiconRef(path))}: ${camelcased}Schema;\n`;
197
165
  file.ambients += ` }\n`;
198
166
  file.ambients += `}`;
199
167
  break;
200
168
  }
201
169
  case 'token': {
202
- result = `${PURE} v.literal(${lit(toLexUri(path))})`;
170
+ result = `${PURE} v.literal(${lit(formatLexiconRef(path))})`;
203
171
  break;
204
172
  }
205
173
  case 'permission-set': {
@@ -358,7 +326,7 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
358
326
  if (file.exports) {
359
327
  generatedIds.add(doc.id);
360
328
 
361
- files.push({
329
+ yield {
362
330
  filename: filename,
363
331
  code:
364
332
  file.imports +
@@ -376,7 +344,7 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
376
344
  file.sinterfaces +
377
345
  `\n\n` +
378
346
  file.ambients,
379
- });
347
+ };
380
348
  }
381
349
  }
382
350
 
@@ -391,40 +359,37 @@ export const generateLexiconApi = async (opts: LexiconApiOptions): Promise<Lexic
391
359
  code += `export * as ${toTitleCase(doc.id)} from ${lit(`./types/${doc.id.replaceAll('.', '/')}${importExt}`)};\n`;
392
360
  }
393
361
 
394
- files.push({
362
+ yield {
395
363
  filename: 'index.ts',
396
364
  code: code,
397
- });
398
- }
399
-
400
- if (opts.prettier) {
401
- const config = await prettier.resolveConfig(opts.prettier.cwd, { editorconfig: true });
402
-
403
- for (const file of files) {
404
- const formatted = await prettier.format(file.code, { ...config, parser: 'typescript' });
405
- file.code = formatted;
406
- }
365
+ };
407
366
  }
367
+ }
408
368
 
409
- return { files };
410
- };
411
-
412
- const generateXrpcQuery = (imports: ImportSet, path: LexPath, spec: LexXrpcQuery): string => {
369
+ const generateXrpcQuery = (imports: ImportSet, path: ParsedLexiconRef, spec: LexXrpcQuery): string => {
413
370
  const params = generateXrpcParameters(imports, path, spec.parameters);
414
371
  const output = generateXrpcBody(imports, path, spec.output);
415
372
 
416
- return `${PURE} v.query(${lit(toLexUri(path))}, {\n"params": ${params}, "output": ${output} })`;
373
+ return `${PURE} v.query(${lit(formatLexiconRef(path))}, {\n"params": ${params}, "output": ${output} })`;
417
374
  };
418
375
 
419
- const generateXrpcProcedure = (imports: ImportSet, path: LexPath, spec: LexXrpcProcedure): string => {
376
+ const generateXrpcProcedure = (
377
+ imports: ImportSet,
378
+ path: ParsedLexiconRef,
379
+ spec: LexXrpcProcedure,
380
+ ): string => {
420
381
  const params = generateXrpcParameters(imports, path, spec.parameters);
421
382
  const input = generateXrpcBody(imports, path, spec.input);
422
383
  const output = generateXrpcBody(imports, path, spec.output);
423
384
 
424
- return `${PURE} v.procedure(${lit(toLexUri(path))}, {\n"params": ${params}, "input": ${input}, "output": ${output} })`;
385
+ return `${PURE} v.procedure(${lit(formatLexiconRef(path))}, {\n"params": ${params}, "input": ${input}, "output": ${output} })`;
425
386
  };
426
387
 
427
- const generateXrpcSubscription = (imports: ImportSet, path: LexPath, spec: LexXrpcSubscription): string => {
388
+ const generateXrpcSubscription = (
389
+ imports: ImportSet,
390
+ path: ParsedLexiconRef,
391
+ spec: LexXrpcSubscription,
392
+ ): string => {
428
393
  const schema = spec.message?.schema;
429
394
 
430
395
  const params = generateXrpcParameters(imports, path, spec.parameters);
@@ -441,10 +406,14 @@ const generateXrpcSubscription = (imports: ImportSet, path: LexPath, spec: LexXr
441
406
  inner += `"message": null,`;
442
407
  }
443
408
 
444
- return `${PURE} v.subscription(${lit(toLexUri(path))}, {\n${inner}})`;
409
+ return `${PURE} v.subscription(${lit(formatLexiconRef(path))}, {\n${inner}})`;
445
410
  };
446
411
 
447
- const generateXrpcBody = (imports: ImportSet, path: LexPath, spec: LexXrpcBody | undefined): string => {
412
+ const generateXrpcBody = (
413
+ imports: ImportSet,
414
+ path: ParsedLexiconRef,
415
+ spec: LexXrpcBody | undefined,
416
+ ): string => {
448
417
  if (spec === undefined) {
449
418
  return `null`;
450
419
  }
@@ -489,7 +458,7 @@ const generateXrpcBody = (imports: ImportSet, path: LexPath, spec: LexXrpcBody |
489
458
 
490
459
  const generateXrpcParameters = (
491
460
  imports: ImportSet,
492
- path: LexPath,
461
+ path: ParsedLexiconRef,
493
462
  spec: LexXrpcParameters | undefined,
494
463
  ): string => {
495
464
  if (spec === undefined) {
@@ -529,7 +498,7 @@ const generateXrpcParameters = (
529
498
  return generateObject(imports, path, mask, 'none');
530
499
  };
531
500
 
532
- const generateRecord = (imports: ImportSet, path: LexPath, spec: LexRecord): string => {
501
+ const generateRecord = (imports: ImportSet, path: ParsedLexiconRef, spec: LexRecord): string => {
533
502
  const schema = generateObject(imports, path, spec.record, 'required');
534
503
 
535
504
  let key = `${PURE} v.string()`;
@@ -548,7 +517,7 @@ const generateRecord = (imports: ImportSet, path: LexPath, spec: LexRecord): str
548
517
 
549
518
  const generateObject = (
550
519
  imports: ImportSet,
551
- path: LexPath,
520
+ path: ParsedLexiconRef,
552
521
  spec: LexObject,
553
522
  writeType: 'required' | 'optional' | 'none' = 'optional',
554
523
  ): string => {
@@ -559,11 +528,11 @@ const generateObject = (
559
528
 
560
529
  switch (writeType) {
561
530
  case 'optional': {
562
- inner += `"$type": ${PURE} v.optional(${PURE} v.literal(${lit(toLexUri(path))})),`;
531
+ inner += `"$type": ${PURE} v.optional(${PURE} v.literal(${lit(formatLexiconRef(path))})),`;
563
532
  break;
564
533
  }
565
534
  case 'required': {
566
- inner += `"$type": ${PURE} v.literal(${lit(toLexUri(path))}),`;
535
+ inner += `"$type": ${PURE} v.literal(${lit(formatLexiconRef(path))}),`;
567
536
  break;
568
537
  }
569
538
  }
@@ -715,7 +684,12 @@ const generateJsdocField = (spec: LexUserType | LexRefVariant | LexUnknown) => {
715
684
  return res;
716
685
  };
717
686
 
718
- const generateType = (imports: ImportSet, path: LexPath, spec: LexDefinableField, lazy = false): string => {
687
+ const generateType = (
688
+ imports: ImportSet,
689
+ path: ParsedLexiconRef,
690
+ spec: LexDefinableField,
691
+ lazy = false,
692
+ ): string => {
719
693
  switch (spec.type) {
720
694
  // LexRefVariant
721
695
  case 'ref': {
@@ -732,8 +706,9 @@ const generateType = (imports: ImportSet, path: LexPath, spec: LexDefinableField
732
706
  const refs = spec.refs
733
707
  .map((ref) => {
734
708
  const refPath = resolvePath(path, ref);
735
- return { path: refPath, uri: toLexUri(refPath) };
709
+ return { path: refPath, uri: formatLexiconRef(refPath) };
736
710
  })
711
+ // oxlint-disable-next-line unicorn/no-array-sort -- map already clones
737
712
  .sort((a, b) => {
738
713
  if (a.uri < b.uri) {
739
714
  return -1;
@@ -2,16 +2,17 @@ import * as fs from 'node:fs/promises';
2
2
  import * as path from 'node:path';
3
3
 
4
4
  import type { LexiconDoc } from '@atcute/lexicon-doc';
5
+
5
6
  import { merge, object } from '@optique/core/constructs';
6
7
  import { message } from '@optique/core/message';
7
8
  import { type InferValue } from '@optique/core/parser';
8
9
  import { command, constant } from '@optique/core/primitives';
9
10
  import pc from 'picocolors';
10
- import prettier from 'prettier';
11
11
 
12
- import { loadConfig, type ExportConfig, type NormalizedConfig } from '../config.js';
13
- import { loadLexicons } from '../lexicon-loader.js';
14
- import { sharedOptions } from '../shared-options.js';
12
+ import { loadConfig, type ExportConfig, type NormalizedConfig } from '../config.ts';
13
+ import { createFormatter, type Formatter } from '../formatter.ts';
14
+ import { loadLexicons } from '../lexicon-loader.ts';
15
+ import { sharedOptions } from '../shared-options.ts';
15
16
 
16
17
  export const exportCommandSchema = command(
17
18
  'export',
@@ -43,27 +44,17 @@ const ensureExportConfig = (config: NormalizedConfig): ExportConfig => {
43
44
  return config.export;
44
45
  };
45
46
 
46
- /**
47
- * writes a lexicon document to disk as formatted JSON
48
- * @param outdir output directory
49
- * @param nsid the NSID of the lexicon
50
- * @param doc the lexicon document
51
- * @param prettierConfig prettier configuration
52
- */
53
47
  const writeLexicon = async (
54
48
  outdir: string,
55
49
  nsid: string,
56
50
  doc: LexiconDoc,
57
- prettierConfig: prettier.Options | null,
51
+ formatter: Formatter,
58
52
  ): Promise<void> => {
59
53
  const nsidPath = nsid.replaceAll('.', '/');
60
54
  const target = path.join(outdir, `${nsidPath}.json`);
61
55
  const dirname = path.dirname(target);
62
56
 
63
- const code = await prettier.format(JSON.stringify(doc, null, 2), {
64
- ...(prettierConfig ?? {}),
65
- parser: 'json',
66
- });
57
+ const code = await formatter.format(JSON.stringify(doc, null, 2), target);
67
58
 
68
59
  await fs.mkdir(dirname, { recursive: true });
69
60
  await fs.writeFile(target, code);
@@ -80,7 +71,7 @@ export const runExport = async (args: ExportCommand): Promise<void> => {
80
71
  // use export.files if specified, otherwise fall back to root files config
81
72
  const files = exportConfig.files ?? config.files;
82
73
  const outdir = path.resolve(config.root, exportConfig.outdir);
83
- const prettierConfig = await prettier.resolveConfig(config.root, { editorconfig: true });
74
+ const formatter = await createFormatter(config.formatter, config.root);
84
75
 
85
76
  // load lexicons from files
86
77
  const loaded = await loadLexicons(files, config.root);
@@ -98,9 +89,7 @@ export const runExport = async (args: ExportCommand): Promise<void> => {
98
89
  await fs.mkdir(outdir, { recursive: true });
99
90
 
100
91
  // write each lexicon as JSON
101
- for (const { nsid, doc } of loaded) {
102
- await writeLexicon(outdir, nsid, doc, prettierConfig);
103
- }
92
+ await Promise.all(loaded.map(({ nsid, doc }) => writeLexicon(outdir, nsid, doc, formatter)));
104
93
 
105
94
  console.log(pc.green(`exported ${loaded.length} lexicon(s) to ${outdir}`));
106
95
  };
@@ -7,11 +7,12 @@ import { type InferValue } from '@optique/core/parser';
7
7
  import { command, constant } from '@optique/core/primitives';
8
8
  import pc from 'picocolors';
9
9
 
10
- import { generateLexiconApi, type ImportMapping } from '../codegen.js';
11
- import { loadConfig } from '../config.js';
12
- import { loadLexicons } from '../lexicon-loader.js';
13
- import { packageJsonSchema } from '../lexicon-metadata.js';
14
- import { sharedOptions } from '../shared-options.js';
10
+ import { generateLexiconApi, type ImportMapping } from '../codegen.ts';
11
+ import { loadConfig } from '../config.ts';
12
+ import { createFormatter } from '../formatter.ts';
13
+ import { loadLexicons } from '../lexicon-loader.ts';
14
+ import { packageJsonSchema } from '../lexicon-metadata.ts';
15
+ import { sharedOptions } from '../shared-options.ts';
15
16
 
16
17
  /**
17
18
  * resolves package imports to ImportMapping[]
@@ -147,24 +148,27 @@ export const runGenerate = async (args: GenerateCommand): Promise<void> => {
147
148
  const loaded = await loadLexicons(config.files, config.root);
148
149
  const documents = loaded.map((l) => l.doc);
149
150
 
150
- const generationResult = await generateLexiconApi({
151
+ const outdir = path.join(config.root, config.outdir);
152
+ const formatter = await createFormatter(config.formatter, config.root);
153
+ const pending: Promise<void>[] = [];
154
+
155
+ for (const file of generateLexiconApi({
151
156
  documents: documents,
152
157
  mappings: allMappings,
153
158
  modules: {
154
159
  importSuffix: config.modules?.importSuffix ?? '.js',
155
160
  },
156
- prettier: {
157
- cwd: process.cwd(),
158
- },
159
- });
160
-
161
- const outdir = path.join(config.root, config.outdir);
162
-
163
- for (const file of generationResult.files) {
161
+ })) {
164
162
  const filename = path.join(outdir, file.filename);
165
- const dirname = path.dirname(filename);
166
163
 
167
- await fs.mkdir(dirname, { recursive: true });
168
- await fs.writeFile(filename, file.code);
164
+ pending.push(
165
+ (async () => {
166
+ const formatted = await formatter.format(file.code, filename);
167
+ await fs.mkdir(path.dirname(filename), { recursive: true });
168
+ await fs.writeFile(filename, formatted);
169
+ })(),
170
+ );
169
171
  }
172
+
173
+ await Promise.all(pending);
170
174
  };
@@ -2,18 +2,19 @@ import * as fs from 'node:fs/promises';
2
2
  import * as path from 'node:path';
3
3
 
4
4
  import { lexiconDoc, refineLexiconDoc, type LexiconDoc } from '@atcute/lexicon-doc';
5
+
5
6
  import { merge, object } from '@optique/core/constructs';
6
7
  import { message } from '@optique/core/message';
7
8
  import { type InferValue } from '@optique/core/parser';
8
9
  import { command, constant } from '@optique/core/primitives';
9
10
  import pc from 'picocolors';
10
- import prettier from 'prettier';
11
11
 
12
- import { loadConfig, type NormalizedConfig, type PullConfig, type SourceConfig } from '../config.js';
13
- import { pullAtprotoSource } from '../pull-sources/atproto.js';
14
- import { pullGitSource } from '../pull-sources/git.js';
15
- import type { PullResult, PulledLexicon, SourceLocation } from '../pull-sources/types.js';
16
- import { sharedOptions } from '../shared-options.js';
12
+ import { loadConfig, type NormalizedConfig, type PullConfig, type SourceConfig } from '../config.ts';
13
+ import { createFormatter, type Formatter } from '../formatter.ts';
14
+ import { pullAtprotoSource } from '../pull-sources/atproto.ts';
15
+ import { pullGitSource } from '../pull-sources/git.ts';
16
+ import type { PullResult, PulledLexicon, SourceLocation } from '../pull-sources/types.ts';
17
+ import { sharedOptions } from '../shared-options.ts';
17
18
 
18
19
  export const pullCommandSchema = command(
19
20
  'pull',
@@ -109,16 +110,13 @@ const writeLexicon = async (
109
110
  outdir: string,
110
111
  nsid: string,
111
112
  doc: LexiconDoc,
112
- prettierConfig: prettier.Options | null,
113
+ formatter: Formatter,
113
114
  ): Promise<void> => {
114
115
  const nsidPath = nsid.replaceAll('.', '/');
115
116
  const target = path.join(outdir, `${nsidPath}.json`);
116
117
  const dirname = path.dirname(target);
117
118
 
118
- const code = await prettier.format(JSON.stringify(doc, null, 2), {
119
- ...(prettierConfig ?? {}),
120
- parser: 'json',
121
- });
119
+ const code = await formatter.format(JSON.stringify(doc, null, 2), target);
122
120
 
123
121
  await fs.mkdir(dirname, { recursive: true });
124
122
  await fs.writeFile(target, code);
@@ -138,7 +136,7 @@ const pullSource = async (source: SourceConfig): Promise<PullResult> => {
138
136
  const writeSourceReadme = async (
139
137
  outdir: string,
140
138
  revisions: SourceRevision[],
141
- prettierConfig: prettier.Options | null,
139
+ formatter: Formatter,
142
140
  ): Promise<void> => {
143
141
  const lines = [
144
142
  '# lexicon sources',
@@ -172,12 +170,10 @@ const writeSourceReadme = async (
172
170
  lines.push('');
173
171
 
174
172
  const content = lines.join('\n');
175
- const formatted = await prettier.format(content, {
176
- ...(prettierConfig ?? {}),
177
- parser: 'markdown',
178
- });
173
+ const target = path.join(outdir, 'README.md');
174
+ const formatted = await formatter.format(content, target);
179
175
 
180
- await fs.writeFile(path.join(outdir, 'README.md'), formatted);
176
+ await fs.writeFile(target, formatted);
181
177
  };
182
178
 
183
179
  /**
@@ -189,7 +185,7 @@ export const runPull = async (args: PullCommand): Promise<void> => {
189
185
  const pullConfig = ensurePullConfig(config);
190
186
 
191
187
  const outdir = path.resolve(config.root, pullConfig.outdir);
192
- const prettierConfig = await prettier.resolveConfig(config.root, { editorconfig: true });
188
+ const formatter = await createFormatter(config.formatter, config.root);
193
189
 
194
190
  const seen = new Map<string, SourceLocation>();
195
191
  const collected: PulledLexicon[] = [];
@@ -223,9 +219,8 @@ export const runPull = async (args: PullCommand): Promise<void> => {
223
219
 
224
220
  await fs.mkdir(outdir, { recursive: true });
225
221
 
226
- for (const entry of collected) {
227
- await writeLexicon(outdir, entry.nsid, entry.doc, prettierConfig);
228
- }
229
-
230
- await writeSourceReadme(outdir, sourceRevisions, prettierConfig);
222
+ await Promise.all([
223
+ ...collected.map((entry) => writeLexicon(outdir, entry.nsid, entry.doc, formatter)),
224
+ writeSourceReadme(outdir, sourceRevisions, formatter),
225
+ ]);
231
226
  };
package/src/config.ts CHANGED
@@ -1,14 +1,15 @@
1
1
  import * as fs from 'node:fs/promises';
2
+ import { availableParallelism } from 'node:os';
2
3
  import * as path from 'node:path';
3
4
  import * as url from 'node:url';
4
5
 
5
- import * as v from '@badrap/valita';
6
- import pc from 'picocolors';
7
-
8
6
  import { isAtprotoDid } from '@atcute/identity';
9
7
  import { isHandle, isNsid } from '@atcute/lexicons/syntax';
10
8
 
11
- import type { ImportMapping } from './codegen.js';
9
+ import * as v from '@badrap/valita';
10
+ import pc from 'picocolors';
11
+
12
+ import type { ImportMapping } from './codegen.ts';
12
13
 
13
14
  const gitSourceConfigSchema = v.object({
14
15
  type: v.literal('git'),
@@ -63,6 +64,18 @@ const exportConfigSchema = v.object({
63
64
  clean: v.boolean().optional(),
64
65
  });
65
66
 
67
+ const formatterConfigSchema = v.union(
68
+ v.object({ type: v.literal('prettier') }),
69
+ v.object({
70
+ type: v.literal('command'),
71
+ command: v.string().assert((value) => value.length > 0, `must not be empty`),
72
+ concurrency: v
73
+ .number()
74
+ .assert((value) => Number.isInteger(value) && value > 0, `must be a positive integer`)
75
+ .optional(() => availableParallelism()),
76
+ }),
77
+ );
78
+
66
79
  export type GitSourceConfig = v.Infer<typeof gitSourceConfigSchema>;
67
80
  export type AtprotoNsidsSourceConfig = v.Infer<typeof atprotoNsidsSourceConfigSchema>;
68
81
  export type AtprotoAuthoritySourceConfig = v.Infer<typeof atprotoAuthoritySourceConfigSchema>;
@@ -70,6 +83,7 @@ export type AtprotoSourceConfig = v.Infer<typeof atprotoSourceConfigSchema>;
70
83
  export type SourceConfig = v.Infer<typeof sourceConfigSchema>;
71
84
  export type PullConfig = v.Infer<typeof pullConfigSchema>;
72
85
  export type ExportConfig = v.Infer<typeof exportConfigSchema>;
86
+ export type FormatterConfig = v.Infer<typeof formatterConfigSchema>;
73
87
 
74
88
  const isValidLexiconPattern = (pattern: string): boolean => {
75
89
  if (pattern.endsWith('.*')) {
@@ -126,6 +140,7 @@ export const lexiconConfigSchema = v.object({
126
140
  })
127
141
  .partial()
128
142
  .optional(),
143
+ formatter: formatterConfigSchema.optional((): FormatterConfig => ({ type: 'prettier' })),
129
144
  pull: pullConfigSchema.optional(),
130
145
  export: exportConfigSchema.optional(),
131
146
  });