wuchale 0.18.11 → 0.19.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.
@@ -7,13 +7,13 @@ export const varNames = {
7
7
  };
8
8
  export function runtimeVars(wrapFunc, base = varNames.rt) {
9
9
  return {
10
- rtTrans: `${wrapFunc(base)}.t`,
11
- rtTPlural: `${wrapFunc(base)}.tp`,
10
+ rtTrans: `${wrapFunc(base)}`,
11
+ rtTPlural: `${wrapFunc(base)}.p`,
12
12
  rtPlural: `${wrapFunc(base)}._.p`,
13
13
  rtLocale: `${wrapFunc(base)}.l`,
14
- rtCtx: `${wrapFunc(base)}.cx`,
15
- rtTransCtx: `${wrapFunc(base)}.tx`,
16
- rtTransTag: `${wrapFunc(base)}.tt`,
14
+ rtCtx: `${wrapFunc(base)}.c`,
15
+ rtTransCtx: `${wrapFunc(base)}.x`,
16
+ rtTransTag: `${wrapFunc(base)}.t`,
17
17
  /** for when nesting, used in adapters with elements */
18
18
  nestCtx: '_w_ctx_',
19
19
  };
@@ -2,14 +2,13 @@ import type MagicString from "magic-string";
2
2
  import { IndexTracker, Message, type HeuristicDetails, type HeuristicDetailsBase, type HeuristicFunc, type MessageType } from "../adapters.js";
3
3
  import { type RuntimeVars, type CommentDirectives } from "./index.js";
4
4
  type NestedRanges = [number, number, boolean][];
5
- type BasicNode = {
6
- start: number;
7
- end: number;
8
- };
9
5
  type InitProps<NodeT> = {
10
6
  vars: () => RuntimeVars;
11
7
  mstr: MagicString;
12
- getRange: (node: NodeT) => BasicNode;
8
+ getRange: (node: NodeT) => {
9
+ start: number;
10
+ end: number;
11
+ };
13
12
  isText: (node: NodeT) => boolean;
14
13
  isExpression: (node: NodeT) => boolean;
15
14
  isComment: (node: NodeT) => boolean;
@@ -34,7 +33,7 @@ type VisitProps<NodeT> = {
34
33
  attribute?: string;
35
34
  useComponent?: boolean;
36
35
  };
37
- export interface MixedVisitor<NodeT extends BasicNode> extends InitProps<NodeT> {
36
+ export interface MixedVisitor<NodeT> extends InitProps<NodeT> {
38
37
  }
39
38
  export declare class MixedVisitor<NodeT> {
40
39
  constructor(props: InitProps<NodeT>);
@@ -171,7 +171,8 @@ export class MixedVisitor {
171
171
  }
172
172
  if (props.scope === 'attribute' && `'"`.includes(this.mstr.original[lastChildEnd])) {
173
173
  const firstChild = props.children[0];
174
- this.mstr.remove(firstChild.start - 1, firstChild.start);
174
+ const { start } = this.getRange(firstChild);
175
+ this.mstr.remove(start - 1, start);
175
176
  this.mstr.remove(lastChildEnd, lastChildEnd + 1);
176
177
  }
177
178
  this.mstr.appendLeft(lastChildEnd, begin);
@@ -19,10 +19,8 @@ const defaultArgs = {
19
19
  generateLoadID: defaultGenerateLoadID,
20
20
  loader: 'vite',
21
21
  runtime: {
22
- useReactive: ({ nested }) => ({
23
- init: nested ? null : false,
24
- use: false,
25
- }),
22
+ initReactive: ({ nested }) => nested ? null : false,
23
+ useReactive: false,
26
24
  plain: {
27
25
  wrapInit: expr => expr,
28
26
  wrapUse: expr => expr,
@@ -1,18 +1,17 @@
1
1
  import MagicString from "magic-string";
2
2
  import type * as Estree from "acorn";
3
3
  import { Message } from '../adapters.js';
4
- import type { HeuristicDetailsBase, HeuristicFunc, IndexTracker, ScriptDeclType, TransformOutput, HeuristicDetails, RuntimeConf, CatalogExpr, CodePattern, UrlMatcher, HeuristicResultChecked, MessageType } from "../adapters.js";
4
+ import type { HeuristicDetailsBase, HeuristicFunc, IndexTracker, TransformOutput, HeuristicDetails, RuntimeConf, CatalogExpr, CodePattern, UrlMatcher, HeuristicResultChecked, MessageType } from "../adapters.js";
5
5
  import { type RuntimeVars, type CommentDirectives } from "../adapter-utils/index.js";
6
6
  export declare const scriptParseOptions: Estree.Options;
7
7
  export declare function scriptParseOptionsWithComments(): [Estree.Options, Estree.Comment[][]];
8
8
  export declare function parseScript(content: string): [Estree.Program, Estree.Comment[][]];
9
- type InitRuntimeFunc = (file: string, funcName?: string, parentFunc?: string, additional?: object) => string | undefined;
10
- export declare class Transformer {
9
+ type InitRuntimeFunc = (funcName?: string, parentFunc?: string) => string | undefined;
10
+ export declare class Transformer<RTCtxT = {}> {
11
11
  index: IndexTracker;
12
12
  heuristic: HeuristicFunc;
13
13
  content: string;
14
14
  comments: Estree.Comment[][];
15
- filename: string;
16
15
  mstr: MagicString;
17
16
  patterns: CodePattern[];
18
17
  matchUrl: UrlMatcher;
@@ -20,17 +19,12 @@ export declare class Transformer {
20
19
  currentRtVar: string;
21
20
  vars: () => RuntimeVars;
22
21
  commentDirectives: CommentDirectives;
23
- insideProgram: boolean;
24
- declaring?: ScriptDeclType;
25
- currentFuncNested: boolean;
26
- currentFuncDef?: string;
27
- currentCall: string;
28
- currentTopLevelCall?: string;
22
+ heuristciDetails: HeuristicDetails;
29
23
  /** .start of the first statements in their respective parents, to put the runtime init before */
30
24
  realBodyStarts: Set<number>;
31
- /** for subclasses. right now for svelte, if in <script module> */
32
- additionalState: object;
33
- constructor(content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, patterns: CodePattern[], catalogExpr: CatalogExpr, rtConf: RuntimeConf, matchUrl: UrlMatcher, rtBaseVars?: string[]);
25
+ /** will be passed to decide which runtime variable to use */
26
+ runtimeCtx: RTCtxT;
27
+ constructor(content: string, filename: string, index: IndexTracker, heuristic: HeuristicFunc, patterns: CodePattern[], catalogExpr: CatalogExpr, rtConf: RuntimeConf<RTCtxT>, matchUrl: UrlMatcher, rtBaseVars?: string[]);
34
28
  fullHeuristicDetails: (detailsBase: HeuristicDetailsBase) => HeuristicDetails;
35
29
  getHeuristicMessageType: (msg: Message) => HeuristicResultChecked;
36
30
  checkHeuristic: (msgStr: string, detailsBase: HeuristicDetailsBase) => [MessageType, Message] | [false, null];
@@ -45,7 +45,6 @@ export class Transformer {
45
45
  content;
46
46
  /* for when the comments are not parsed as part of the AST */
47
47
  comments = [];
48
- filename;
49
48
  mstr;
50
49
  patterns;
51
50
  matchUrl;
@@ -54,27 +53,22 @@ export class Transformer {
54
53
  vars;
55
54
  // state
56
55
  commentDirectives = {};
57
- insideProgram = false;
58
- declaring;
59
- currentFuncNested = false;
60
- currentFuncDef;
61
- currentCall;
62
- currentTopLevelCall;
56
+ heuristciDetails = { file: '', scope: 'script', insideProgram: true };
63
57
  /** .start of the first statements in their respective parents, to put the runtime init before */
64
58
  realBodyStarts = new Set();
65
- /** for subclasses. right now for svelte, if in <script module> */
66
- additionalState = {};
59
+ /** will be passed to decide which runtime variable to use */
60
+ runtimeCtx = {};
67
61
  constructor(content, filename, index, heuristic, patterns, catalogExpr, rtConf, matchUrl, rtBaseVars = [varNames.rt]) {
68
62
  this.index = index;
69
63
  this.heuristic = heuristic;
70
64
  this.patterns = patterns;
71
65
  this.content = content;
72
- this.filename = filename;
66
+ this.heuristciDetails.file = filename;
73
67
  this.matchUrl = matchUrl;
74
- const topLevelUseReactive = rtConf.useReactive({
68
+ const topLevelUseReactive = typeof rtConf.useReactive === 'boolean' ? () => rtConf.useReactive : ({
75
69
  nested: false,
76
70
  file: filename,
77
- additional: this.additionalState,
71
+ ctx: this.runtimeCtx,
78
72
  });
79
73
  const vars = {};
80
74
  // to enable the use of different runtime vars for different places, right now for svelte <script module>s
@@ -86,35 +80,36 @@ export class Transformer {
86
80
  }
87
81
  this.currentRtVar = rtBaseVars[0];
88
82
  this.vars = () => {
89
- const useReactive = rtConf.useReactive({
90
- funcName: this.currentFuncDef,
91
- nested: this.currentFuncNested,
83
+ const useReactive = typeof rtConf.useReactive === 'boolean' ? rtConf.useReactive : rtConf.useReactive({
84
+ funcName: this.heuristciDetails.funcName ?? undefined,
85
+ nested: this.heuristciDetails.funcIsNested ?? false,
92
86
  file: filename,
93
- additional: this.additionalState,
87
+ ...this.runtimeCtx,
94
88
  }) ?? topLevelUseReactive;
95
89
  const currentVars = vars[this.currentRtVar];
96
- return useReactive.use ? currentVars.reactive : currentVars.plain;
90
+ return useReactive ? currentVars.reactive : currentVars.plain;
97
91
  };
98
- this.initRuntime = (file, funcName, parentFunc, additional) => {
99
- const useReactive = rtConf.useReactive({ funcName, nested: parentFunc != null, file, additional: additional ?? {} });
100
- if (useReactive.init == null) {
92
+ this.initRuntime = (funcName, parentFunc) => {
93
+ let initReactive = rtConf.initReactive({
94
+ funcName,
95
+ nested: parentFunc != null,
96
+ file: filename,
97
+ ...this.runtimeCtx,
98
+ });
99
+ if (initReactive == null) {
101
100
  return;
102
101
  }
103
- const wrapInit = useReactive.init ? rtConf.reactive.wrapInit : rtConf.plain.wrapInit;
104
- const expr = useReactive.init ? catalogExpr.reactive : catalogExpr.plain;
102
+ if (typeof rtConf.useReactive === 'boolean') {
103
+ initReactive = rtConf.useReactive; // should be consistent
104
+ }
105
+ const wrapInit = initReactive ? rtConf.reactive.wrapInit : rtConf.plain.wrapInit;
106
+ const expr = initReactive ? catalogExpr.reactive : catalogExpr.plain;
105
107
  return `\nconst ${this.currentRtVar} = ${wrapInit(expr)}\n`;
106
108
  };
107
109
  }
108
110
  fullHeuristicDetails = (detailsBase) => {
109
- const details = {
110
- file: this.filename,
111
- call: this.currentCall,
112
- declaring: this.declaring,
113
- funcName: this.currentFuncDef,
114
- topLevelCall: this.currentTopLevelCall,
115
- ...detailsBase
116
- };
117
- if (details.declaring == null && this.insideProgram) {
111
+ const details = { ...this.heuristciDetails, ...detailsBase };
112
+ if (details.declaring == null && details.insideProgram) {
118
113
  details.declaring = 'expression';
119
114
  }
120
115
  return details;
@@ -182,12 +177,12 @@ export class Transformer {
182
177
  visitNewExpression = (node) => node.arguments.map(this.visit).flat();
183
178
  defaultVisitCallExpression = (node) => {
184
179
  const msgs = this.visit(node.callee);
185
- const currentCall = this.currentCall;
186
- this.currentCall = this.getCalleeName(node.callee);
180
+ const currentCall = this.heuristciDetails.call;
181
+ this.heuristciDetails.call = this.getCalleeName(node.callee);
187
182
  for (const arg of node.arguments) {
188
183
  msgs.push(...this.visit(arg));
189
184
  }
190
- this.currentCall = currentCall; // restore
185
+ this.heuristciDetails.call = currentCall; // restore
191
186
  return msgs;
192
187
  };
193
188
  visitCallExpression = (node) => {
@@ -368,25 +363,25 @@ export class Transformer {
368
363
  return `[${callee.type}]`;
369
364
  };
370
365
  defaultVisitVariableDeclarator = (node) => {
371
- let atTopLevelDefn = this.insideProgram && !this.declaring;
366
+ let atTopLevelDefn = this.heuristciDetails.insideProgram && !this.heuristciDetails.declaring;
372
367
  if (!node.init) {
373
368
  return [];
374
369
  }
375
370
  if (atTopLevelDefn) {
376
371
  if (node.init.type === 'ArrowFunctionExpression' || node.init.type === 'FunctionExpression') {
377
- this.declaring = 'function';
372
+ this.heuristciDetails.declaring = 'function';
378
373
  }
379
374
  else {
380
- this.declaring = 'variable';
375
+ this.heuristciDetails.declaring = 'variable';
381
376
  if (node.init.type === 'CallExpression') {
382
- this.currentTopLevelCall = this.getCalleeName(node.init.callee);
377
+ this.heuristciDetails.topLevelCall = this.getCalleeName(node.init.callee);
383
378
  }
384
379
  }
385
380
  }
386
381
  const msgs = [...this.visit(node.id), ...this.visit(node.init)];
387
382
  if (atTopLevelDefn) {
388
- this.currentTopLevelCall = undefined; // reset
389
- this.declaring = undefined;
383
+ this.heuristciDetails.topLevelCall = undefined; // reset
384
+ this.heuristciDetails.declaring = undefined;
390
385
  }
391
386
  return msgs;
392
387
  };
@@ -432,13 +427,13 @@ export class Transformer {
432
427
  return nonLiteralStart ?? nodes[0]?.start;
433
428
  };
434
429
  visitFunctionBody = (node, name, end) => {
435
- const prevFuncDef = this.currentFuncDef;
436
- const prevFuncNested = this.currentFuncNested;
437
- this.currentFuncDef = name;
438
- this.currentFuncNested = name != null && prevFuncDef != null;
430
+ const prevFuncDef = this.heuristciDetails.funcName;
431
+ const prevFuncNested = this.heuristciDetails.funcIsNested;
432
+ this.heuristciDetails.funcName = name;
433
+ this.heuristciDetails.funcIsNested = name != null && prevFuncDef != null;
439
434
  const msgs = this.visit(node);
440
435
  if (msgs.length > 0) {
441
- const initRuntime = this.initRuntime(this.filename, this.currentFuncDef, prevFuncDef, this.additionalState);
436
+ const initRuntime = this.initRuntime(this.heuristciDetails.funcName, prevFuncDef ?? undefined);
442
437
  if (initRuntime) {
443
438
  if (node.type === 'BlockStatement') {
444
439
  this.mstr.prependLeft(this.getRealBodyStart(node.body) ?? node.start, initRuntime);
@@ -461,15 +456,15 @@ export class Transformer {
461
456
  }
462
457
  }
463
458
  }
464
- this.currentFuncNested = prevFuncNested;
465
- this.currentFuncDef = prevFuncDef;
459
+ this.heuristciDetails.funcIsNested = prevFuncNested;
460
+ this.heuristciDetails.funcName = prevFuncDef;
466
461
  return msgs;
467
462
  };
468
463
  visitFunctionDeclaration = (node) => {
469
- const declaring = this.declaring;
470
- this.declaring = 'function';
464
+ const declaring = this.heuristciDetails.declaring;
465
+ this.heuristciDetails.declaring = 'function';
471
466
  const msgs = this.visitFunctionBody(node.body, node.id?.name ?? '');
472
- this.declaring = declaring;
467
+ this.heuristciDetails.declaring = declaring;
473
468
  return msgs;
474
469
  };
475
470
  visitArrowFunctionExpression = (node) => this.visitFunctionBody(node.body, '', node.end);
@@ -486,8 +481,8 @@ export class Transformer {
486
481
  };
487
482
  visitClassDeclaration = (node) => {
488
483
  const msgs = [];
489
- const prevDecl = this.declaring;
490
- this.declaring = 'class';
484
+ const prevDecl = this.heuristciDetails.declaring;
485
+ this.heuristciDetails.declaring = 'class';
491
486
  for (const body of node.body.body) {
492
487
  if (body.type === 'MethodDefinition') {
493
488
  msgs.push(...this.visit(body.key));
@@ -497,13 +492,13 @@ export class Transformer {
497
492
  }
498
493
  }
499
494
  else if (body.type === 'StaticBlock') {
500
- const currentFuncDef = this.currentFuncDef;
501
- this.currentFuncDef = `${node.id.name}.[static]`;
495
+ const currentFuncDef = this.heuristciDetails.funcName;
496
+ this.heuristciDetails.funcName = `${node.id.name}.[static]`;
502
497
  msgs.push(...body.body.map(this.visit).flat());
503
- this.currentFuncDef = currentFuncDef; // restore
498
+ this.heuristciDetails.funcName = currentFuncDef; // restore
504
499
  }
505
500
  }
506
- this.declaring = prevDecl; // restore
501
+ this.heuristciDetails.declaring = prevDecl; // restore
507
502
  return msgs;
508
503
  };
509
504
  checkHeuristicTemplateLiteral = (node, heurDetails) => {
@@ -568,8 +563,8 @@ export class Transformer {
568
563
  return msgs;
569
564
  };
570
565
  visitTaggedTemplateExpression = (node) => {
571
- const prevCall = this.currentCall;
572
- this.currentCall = this.getCalleeName(node.tag);
566
+ const prevCall = this.heuristciDetails.call;
567
+ this.heuristciDetails.call = this.getCalleeName(node.tag);
573
568
  let msgs = [];
574
569
  const heuRes = this.checkHeuristicTemplateLiteral(node.quasi);
575
570
  if (heuRes) {
@@ -586,7 +581,7 @@ export class Transformer {
586
581
  this.mstr.update(start, end, `, ${index})`);
587
582
  }
588
583
  }
589
- this.currentCall = prevCall;
584
+ this.heuristciDetails.call = prevCall;
590
585
  return msgs;
591
586
  };
592
587
  visitSwitchStatement = (node) => node.cases.map(c => c.consequent.map(this.visit)).flat().flat();
@@ -603,9 +598,9 @@ export class Transformer {
603
598
  visitTSAsExpression = (node) => this.visit(node.expression);
604
599
  visitTSTypeAssertion = (node) => this.visit(node.expression);
605
600
  visitProgram = (node) => {
606
- this.insideProgram = true;
601
+ this.heuristciDetails.insideProgram = true;
607
602
  const msgs = this.visitStatementsNSaveRealBodyStart(node.body);
608
- this.insideProgram = false;
603
+ this.heuristciDetails.insideProgram = false;
609
604
  return msgs;
610
605
  };
611
606
  visitWithCommentDirectives = (node, func) => {
@@ -11,6 +11,8 @@ export type HeuristicDetails = HeuristicDetailsBase & {
11
11
  file: string;
12
12
  declaring?: ScriptDeclType;
13
13
  funcName?: string | null;
14
+ funcIsNested?: boolean;
15
+ insideProgram: boolean;
14
16
  topLevelCall?: string;
15
17
  call?: string;
16
18
  };
@@ -43,7 +45,7 @@ export declare const defaultHeuristic: HeuristicFunc;
43
45
  export declare const defaultHeuristicFuncOnly: HeuristicFunc;
44
46
  export declare const defaultGenerateLoadID: (filename: string) => string;
45
47
  export declare class IndexTracker {
46
- indices: Record<string, number>;
48
+ indices: Map<string, number>;
47
49
  nextIndex: number;
48
50
  get: (msgStr: string) => number;
49
51
  }
@@ -55,9 +57,6 @@ export type CatalogExpr = {
55
57
  plain: string;
56
58
  reactive: string;
57
59
  };
58
- export type TransformHeader = {
59
- head: string;
60
- };
61
60
  export type UrlMatcher = (url: string) => string | null | undefined;
62
61
  type TransformCtx = {
63
62
  content: string;
@@ -81,22 +80,19 @@ export type TransformOutput = {
81
80
  export type TransformFunc = (expr: TransformCtx) => TransformOutput;
82
81
  export type TransformFuncAsync = (expr: TransformCtx) => Promise<TransformOutput>;
83
82
  export type WrapFunc = (expr: string) => string;
84
- export type UseReactiveFunc = (details: {
83
+ export type DecideReactiveDetails<RTCtxT> = RTCtxT & {
85
84
  funcName?: string;
86
85
  nested: boolean;
87
86
  file: string;
88
- additional: object;
89
- }) => {
90
- /** null to disable initializing */
91
- init: boolean | null;
92
- use: boolean;
93
87
  };
94
88
  type RuntimeConfDetails = {
95
89
  wrapInit: WrapFunc;
96
90
  wrapUse: WrapFunc;
97
91
  };
98
- export type RuntimeConf = {
99
- useReactive: UseReactiveFunc;
92
+ export type RuntimeConf<RTCtxT = {}> = {
93
+ /** return null to disable */
94
+ initReactive: (details: DecideReactiveDetails<RTCtxT>) => boolean | null;
95
+ useReactive: boolean | ((details: DecideReactiveDetails<RTCtxT>) => boolean);
100
96
  plain: RuntimeConfDetails;
101
97
  reactive: RuntimeConfDetails;
102
98
  };
@@ -104,7 +100,8 @@ export type LoaderPath = {
104
100
  client: string;
105
101
  server: string;
106
102
  };
107
- export type AdapterPassThruOpts = {
103
+ export type AdapterPassThruOpts<RTCtxT extends {} = {}> = {
104
+ sourceLocale?: string;
108
105
  files: GlobConf;
109
106
  localesDir: string;
110
107
  /** if writing transformed code to a directory is desired, specify this */
@@ -116,9 +113,9 @@ export type AdapterPassThruOpts = {
116
113
  localize?: boolean | URLLocalizer;
117
114
  };
118
115
  generateLoadID: (filename: string) => string;
119
- runtime: Partial<RuntimeConf>;
116
+ runtime: Partial<RuntimeConf<RTCtxT>>;
120
117
  };
121
- export type Adapter = AdapterPassThruOpts & {
118
+ export type Adapter<RTCtxT extends {} = {}> = AdapterPassThruOpts<RTCtxT> & {
122
119
  transform: TransformFunc | TransformFuncAsync;
123
120
  /** possible filename extensions for loader. E.g. `.js` */
124
121
  loaderExts: string[];
@@ -132,7 +129,7 @@ export type CodePattern = {
132
129
  args: ('message' | 'pluralFunc' | 'locale' | 'other')[];
133
130
  };
134
131
  export type LoaderChoice<LoadersAvailable> = LoadersAvailable | string & {} | 'custom';
135
- export type AdapterArgs<LoadersAvailable> = AdapterPassThruOpts & {
132
+ export type AdapterArgs<LoadersAvailable, RTCtxT extends {} = {}> = AdapterPassThruOpts<RTCtxT> & {
136
133
  loader: LoaderChoice<LoadersAvailable>;
137
134
  heuristic: HeuristicFunc;
138
135
  patterns: CodePattern[];
package/dist/adapters.js CHANGED
@@ -1,4 +1,4 @@
1
- const someHeuDet = { file: '', scope: 'markup' };
1
+ const someHeuDet = { file: '', scope: 'markup', insideProgram: true };
2
2
  export class Message {
3
3
  msgStr; // array for plurals
4
4
  plural = false;
@@ -93,14 +93,15 @@ export const defaultHeuristicFuncOnly = msg => {
93
93
  };
94
94
  export const defaultGenerateLoadID = (filename) => filename.replace(/[^a-zA-Z0-9_]+/g, '_');
95
95
  export class IndexTracker {
96
- indices = {};
96
+ indices = new Map();
97
97
  nextIndex = 0;
98
98
  get = (msgStr) => {
99
- if (msgStr in this.indices) {
100
- return this.indices[msgStr];
99
+ let index = this.indices.get(msgStr);
100
+ if (index != null) {
101
+ return index;
101
102
  }
102
- const index = this.nextIndex;
103
- this.indices[msgStr] = index;
103
+ index = this.nextIndex;
104
+ this.indices.set(msgStr, index);
104
105
  this.nextIndex++;
105
106
  return index;
106
107
  };
@@ -1,10 +1,11 @@
1
1
  import type { AI } from './index.js';
2
2
  type GeminiOpts = {
3
3
  apiKey?: string;
4
+ model?: string;
4
5
  batchSize?: number;
5
6
  think?: boolean;
6
7
  parallel?: number;
7
8
  };
8
- export declare function gemini({ apiKey, batchSize, think, parallel }?: GeminiOpts): AI | null;
9
+ export declare function gemini({ apiKey, model, batchSize, think, parallel }?: GeminiOpts): AI | null;
9
10
  export declare const defaultGemini: AI | null;
10
11
  export {};
package/dist/ai/gemini.js CHANGED
@@ -1,4 +1,4 @@
1
- const url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent';
1
+ const url = 'https://generativelanguage.googleapis.com/v1beta/models/';
2
2
  const headers = { 'Content-Type': 'application/json' };
3
3
  function prepareData(content, instruction, think) {
4
4
  return {
@@ -13,7 +13,7 @@ function prepareData(content, instruction, think) {
13
13
  }
14
14
  };
15
15
  }
16
- export function gemini({ apiKey = 'env', batchSize = 50, think = false, parallel = 4 } = {}) {
16
+ export function gemini({ apiKey = 'env', model = 'gemini-2.5-flash', batchSize = 50, think = false, parallel = 4 } = {}) {
17
17
  if (apiKey === 'env') {
18
18
  apiKey = process.env.GEMINI_API_KEY ?? '';
19
19
  }
@@ -26,7 +26,7 @@ export function gemini({ apiKey = 'env', batchSize = 50, think = false, parallel
26
26
  parallel,
27
27
  translate: async (content, instruction) => {
28
28
  const data = prepareData(content, instruction, think);
29
- const res = await fetch(url, {
29
+ const res = await fetch(`${url}${model}:generateContent`, {
30
30
  method: 'POST',
31
31
  headers: { ...headers, 'x-goog-api-key': apiKey },
32
32
  body: JSON.stringify(data)
@@ -2,20 +2,21 @@ import { AdapterHandler } from "../handler.js";
2
2
  import { color, Logger } from "../log.js";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import { watch as watchFS } from 'chokidar';
5
- function extractor(handler) {
5
+ function extractor(handler, logger) {
6
6
  const adapterName = color.magenta(handler.key);
7
7
  return async (filename) => {
8
- console.info(`${adapterName}: Extract from ${color.cyan(filename)}`);
8
+ logger.info(`${adapterName}: Extract from ${color.cyan(filename)}`);
9
9
  const contents = await readFile(filename);
10
10
  await handler.transform(contents.toString(), filename);
11
11
  };
12
12
  }
13
13
  export async function extract(config, clean, watch, sync) {
14
- !watch && console.info('Extracting...');
14
+ const logger = new Logger(config.logLevel);
15
+ !watch && logger.info('Extracting...');
15
16
  const handlers = [];
16
- const sharedState = {};
17
+ const sharedState = new Map();
17
18
  for (const [key, adapter] of Object.entries(config.adapters)) {
18
- const handler = new AdapterHandler(adapter, key, config, 'cli', process.cwd(), new Logger(config.logLevel));
19
+ const handler = new AdapterHandler(adapter, key, config, 'cli', process.cwd(), logger);
19
20
  await handler.init(sharedState);
20
21
  handlers.push(handler);
21
22
  }
@@ -24,12 +25,12 @@ export async function extract(config, clean, watch, sync) {
24
25
  await handler.directScanFS(clean, sync);
25
26
  }
26
27
  if (!watch) {
27
- console.info('Extraction finished.');
28
+ logger.info('Extraction finished.');
28
29
  return;
29
30
  }
30
31
  // watch
31
- console.info('Watching for changes');
32
- const handlersWithExtr = handlers.map(h => [h.fileMatches, extractor(h)]);
32
+ logger.info('Watching for changes');
33
+ const handlersWithExtr = handlers.map(h => [h.fileMatches, extractor(h, logger)]);
33
34
  watchFS('.', { ignoreInitial: true }).on('all', async (event, filename) => {
34
35
  if (!['add', 'change'].includes(event)) {
35
36
  return;
package/dist/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { defaultConfigNames, getConfig } from "../config.js";
3
3
  import { parseArgs } from 'node:util';
4
- import { color } from "../log.js";
4
+ import { color, logLevels } from "../log.js";
5
5
  import { extract } from "./extract.js";
6
6
  import { status } from "./status.js";
7
7
  const { positionals, values } = parseArgs({
@@ -23,6 +23,11 @@ const { positionals, values } = parseArgs({
23
23
  type: 'boolean',
24
24
  default: false,
25
25
  },
26
+ 'log-level': {
27
+ type: 'string',
28
+ short: 'l',
29
+ default: 'info',
30
+ },
26
31
  help: {
27
32
  type: 'boolean',
28
33
  short: 'h',
@@ -41,16 +46,17 @@ Commands:
41
46
  ${color.cyan('status')} Show current status
42
47
 
43
48
  Options:
44
- ${color.cyan('--config')} use another config file instead of ${defaultConfigNames.map(color.cyan).join('|')}
45
- ${color.cyan('--clean')}, ${color.cyan('-c')} (only when no commands) remove unused messages from catalogs
46
- ${color.cyan('--watch')}, ${color.cyan('-w')} (only when no commands) continuously watch for file changes
47
- ${color.cyan('--sync')} (only when no commands) extract sequentially instead of in parallel
48
- ${color.cyan('--help')}, ${color.cyan('-h')} Show this help
49
+ ${color.cyan('--config')} use another config file instead of ${defaultConfigNames.map(color.cyan).join('|')}
50
+ ${color.cyan('--clean')}, ${color.cyan('-c')} (only when no commands) remove unused messages from catalogs
51
+ ${color.cyan('--watch')}, ${color.cyan('-w')} (only when no commands) continuously watch for file changes
52
+ ${color.cyan('--sync')} (only when no commands) extract sequentially instead of in parallel
53
+ ${color.cyan('--log-level')}, ${color.cyan('-l')} {${Object.keys(logLevels).map(color.cyan)}} (only when no commands) set log level
54
+ ${color.cyan('--help')}, ${color.cyan('-h')} Show this help
49
55
  `;
50
56
  async function getConfigNLocales() {
51
57
  const config = await getConfig(values.config);
52
- const locales = [config.sourceLocale, ...config.otherLocales];
53
- return [config, locales];
58
+ config.logLevel = values["log-level"];
59
+ return [config, config.locales];
54
60
  }
55
61
  if (values.help) {
56
62
  console.log('wuchale cli');
package/dist/compile.js CHANGED
@@ -1,3 +1,7 @@
1
+ const OPEN = Symbol();
2
+ const CLOSE = Symbol();
3
+ const SELF_CLOSE = Symbol();
4
+ const PLACEHOLDER = Symbol();
1
5
  const digitRange = ['0', '9'].map(d => d.charCodeAt(0));
2
6
  function extractSpecial(msgStr, start) {
3
7
  const inPlaceHolder = msgStr[start] === '{';
@@ -32,18 +36,18 @@ function extractSpecial(msgStr, start) {
32
36
  if (endChar !== '}') {
33
37
  return [null, null, start];
34
38
  }
35
- return ['placeholder', n, i + 1];
39
+ return [PLACEHOLDER, n, i + 1];
36
40
  }
37
41
  if (endChar === '/' && msgStr[i + 1] === '>') {
38
- return ['selfclose', n, i + 2];
42
+ return [SELF_CLOSE, n, i + 2];
39
43
  }
40
44
  if (endChar != '>') {
41
45
  return [null, null, start];
42
46
  }
43
47
  if (inClose) {
44
- return ['close', n, i + 1];
48
+ return [CLOSE, n, i + 1];
45
49
  }
46
- return ['open', n, i + 1];
50
+ return [OPEN, n, i + 1];
47
51
  }
48
52
  function compile(msgStr, start = 0, parentTag = null) {
49
53
  let curTxt = '';
@@ -63,14 +67,14 @@ function compile(msgStr, start = 0, parentTag = null) {
63
67
  compiled.push(curTxt);
64
68
  curTxt = '';
65
69
  }
66
- if (type === 'open') {
70
+ if (type === OPEN) {
67
71
  currentOpenTag = n;
68
72
  const [subExt, newIc] = compile(msgStr, newI, n);
69
73
  compiled.push([n, ...subExt]);
70
74
  i = newIc;
71
75
  continue;
72
76
  }
73
- if (type === 'close') {
77
+ if (type === CLOSE) {
74
78
  if (currentOpenTag != null) {
75
79
  if (currentOpenTag != n) {
76
80
  throw Error('Closing a different tag');
@@ -84,7 +88,7 @@ function compile(msgStr, start = 0, parentTag = null) {
84
88
  throw Error('Closing a different tag');
85
89
  }
86
90
  }
87
- else if (type === 'selfclose') {
91
+ else if (type === SELF_CLOSE) {
88
92
  compiled.push([n]);
89
93
  }
90
94
  else { // placeholder