polycast-cli 0.2.0 → 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.
package/dist/scan.d.ts CHANGED
@@ -1,27 +1,83 @@
1
1
  /**
2
- * Zero-config source capture: scan Swift files for Polycast-rendered
3
- * string literals so nobody hand-maintains the String Catalog.
2
+ * Zero-config source capture: a Swift-aware lexer + capture engine that
3
+ * finds Polycast-rendered string literals in Swift sources so nobody
4
+ * hand-maintains the String Catalog.
4
5
  *
5
- * Captured calls: Text("…"), PText("…"), Polycast.string("…").
6
- * (With the generated `typealias Text = PText` shadow, plain Text renders
7
- * through Polycast, so its literals belong in the pipeline too.)
6
+ * The lexer understands the real literal grammar — escapes (\n \t \\ \"
7
+ * \r \0 \u{XXXX} decoded), multiline """…""" blocks (closing-delimiter
8
+ * indentation stripped, physical newlines preserved), raw #"…"# /
9
+ * #"""…"""# strings (backslash is literal unless followed by the matching
10
+ * number of #s), nested block comments, and strings containing "//" — so
11
+ * comment handling can never misfire inside a literal.
8
12
  *
9
- * Interpolations become %@ — identical to PolycastFormatString at
10
- * runtime, so scanned keys and rendered keys always agree.
11
- * `Text(verbatim:)` and empty literals are skipped;
12
- * `…, count: n)` marks a plural key.
13
+ * Interpolations `\(…)` become %@ — identical to PolycastFormatString at
14
+ * runtime, so scanned keys and rendered keys always agree byte-for-byte.
15
+ * Parity rule: a literal "%" doubles to "%%" ONLY when the string contains
16
+ * at least one interpolation ("Save 50% off \(deal)" "Save 50%% off %@";
17
+ * a pure literal "Save 50%" stays "Save 50%").
18
+ *
19
+ * Captured shapes:
20
+ * - registered calls (Text, PText, Polycast.string, …): every top-level
21
+ * literal in the balanced argument list — ternary branches, `??`
22
+ * fallbacks, paren-wrapped expressions, 2nd+ positional args. Literals
23
+ * behind a SKIP label (verbatim:, systemImage:, …), inside nested
24
+ * closures `{ … }`, or inside subscripts/collection literals `[ … ]`
25
+ * are not display strings and are skipped.
26
+ * - qualified spellings: SwiftUI.Text(…) and Text.init(…). SwiftUI.-
27
+ * qualified captures are marked `native` (they opt out of the shadow).
28
+ * - Foundation: NSLocalizedString("key", …) (first literal only),
29
+ * String(localized:…), AttributedString(localized:…).
30
+ * - `.prop = "literal"` assignments for a configurable property list.
31
+ * - `: String = "literal"` typed defaults (vars, lets, default params).
32
+ * - `title:`-style registered labels in any argument position.
33
+ * A `comment:`-labelled literal becomes the translator note for its call.
13
34
  */
14
35
  export interface ScannedString {
15
36
  key: string;
16
37
  kind: "simple" | "plural";
17
38
  file: string;
39
+ /** Translator note from a `comment:` argument at the capture site. */
40
+ comment?: string;
41
+ /** Letterless "joiner" key ("%@ – %@"): stored and served in bundles,
42
+ * but skipped by AI drafting. */
43
+ structural?: boolean;
44
+ /** Every occurrence used the SwiftUI-qualified spelling (`SwiftUI.Text`),
45
+ * which opts out of the Polycast shadow — OTA edits won't reach it. */
46
+ native?: boolean;
47
+ }
48
+ export interface ScanStats {
49
+ filesScanned: number;
50
+ dirsSkipped: string[];
51
+ rootsScanned: string[];
52
+ }
53
+ export interface ScanOptions {
54
+ /** Extra capture spellings, same syntax as polycast.json `scanCalls`:
55
+ * "AppText" (call), ".navigationTitle" (method), "title:" (label). */
56
+ extraCalls?: string[];
57
+ /** Property names captured via `.prop = "literal"`; REPLACES
58
+ * DEFAULT_ASSIGN_PROPS when provided. */
59
+ assignProps?: string[];
60
+ /** Directory recursion depth limit (default 12). */
61
+ maxDepth?: number;
62
+ /** Directory names to skip; REPLACES the default skip list when
63
+ * provided. Dot-directories are always skipped. */
64
+ skipDirs?: string[];
65
+ /** Extra roots scanned in addition to `root` (relative paths resolve
66
+ * against `root`). Local SPM path deps from Package.swift are
67
+ * auto-discovered on top of these. */
68
+ extraRoots?: string[];
69
+ /** Per-file predicate over the path relative to the main root (the same
70
+ * value ScannedString.file carries); return false to skip the file.
71
+ * Applied BEFORE capture and cross-file dedupe, so a key denied in one
72
+ * file still survives via its occurrences in allowed files. */
73
+ fileFilter?: (relPath: string) => boolean;
18
74
  }
19
75
  export declare const DEFAULT_SCAN_CALLS: string[];
20
- /** Build the call matcher from default + user-configured component names.
21
- * Plain names ("AppText") match constructor/function calls; names starting
22
- * with "." (".navigationTitle") match method calls. */
23
- export declare function buildCallMatcher(extra?: string[]): RegExp;
76
+ /** `.prop = "literal"` assignment targets captured by default. */
77
+ export declare const DEFAULT_ASSIGN_PROPS: string[];
78
+ export declare function scanSwiftSourcesDetailed(root: string, opts?: ScanOptions): {
79
+ strings: ScannedString[];
80
+ stats: ScanStats;
81
+ };
82
+ /** Back-compat wrapper — same shape the CLI has always consumed. */
24
83
  export declare function scanSwiftSources(root: string, extraCalls?: string[]): ScannedString[];
25
- /** Blank out line and block comments (string-literal aware) so doc
26
- * examples like `Text("…")` never get captured. Nested blocks handled. */
27
- export declare function stripComments(src: string): string;