@vobs/compiler 1.0.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,51 @@
1
+ import ts from 'typescript'
2
+ import type { CompilerPlugin } from './plugin'
3
+
4
+ export interface I18nExtractorOptions {
5
+ readonly functions?: readonly string[]
6
+ readonly onKey?: (key: string, filename: string) => void
7
+ }
8
+
9
+ export interface I18nExtractor {
10
+ readonly plugin: CompilerPlugin
11
+ getKeys(): readonly string[]
12
+ reset(): void
13
+ }
14
+
15
+ /** Collects statically addressable translation keys without changing emitted code. */
16
+ export function createI18nExtractor(options: I18nExtractorOptions = {}): I18nExtractor {
17
+ const names = new Set(options.functions ?? ['t'])
18
+ const keys = new Set<string>()
19
+ const plugin: CompilerPlugin = {
20
+ name: 'i18n-extractor',
21
+ analyze(program, context) {
22
+ const visit = (node: ts.Node): void => {
23
+ if (ts.isCallExpression(node) && isTranslationCall(node.expression, names)) {
24
+ const key = readStaticKey(node.arguments[0])
25
+ if (key) {
26
+ keys.add(key)
27
+ options.onKey?.(key, context.filename)
28
+ }
29
+ }
30
+ ts.forEachChild(node, visit)
31
+ }
32
+ visit(program)
33
+ }
34
+ }
35
+ return {
36
+ plugin,
37
+ getKeys: () => [...keys].sort(),
38
+ reset: () => keys.clear()
39
+ }
40
+ }
41
+
42
+ function isTranslationCall(expression: ts.LeftHandSideExpression, names: Set<string>): boolean {
43
+ if (ts.isIdentifier(expression)) return names.has(expression.text)
44
+ return ts.isPropertyAccessExpression(expression) && names.has(expression.name.text)
45
+ }
46
+
47
+ function readStaticKey(argument: ts.Expression | undefined): string | undefined {
48
+ if (!argument) return undefined
49
+ if (ts.isStringLiteral(argument) || ts.isNoSubstitutionTemplateLiteral(argument)) return argument.text
50
+ return undefined
51
+ }
package/src/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ // @vobs/compiler 入口
2
+
3
+ export { compile, compileWithSourceMap, createCompiler } from './compile.ts'
4
+ export { createI18nExtractor } from './i18n-extractor.ts'
5
+ export type { I18nExtractor, I18nExtractorOptions } from './i18n-extractor.ts'
6
+ export type {
7
+ AnalyzeContext,
8
+ ASTNode,
9
+ CompileResult,
10
+ CompilerDiagnostic,
11
+ CompileOptions,
12
+ CompilerContext,
13
+ CompilerOptions,
14
+ CompilerPlugin,
15
+ Program,
16
+ TransformContext,
17
+ VobsCompiler,
18
+ VobsSourceMap
19
+ } from './plugin.ts'
package/src/plugin.ts ADDED
@@ -0,0 +1,72 @@
1
+ import ts from 'typescript'
2
+
3
+ export type ASTNode = ts.Node
4
+ export type Program = ts.SourceFile
5
+
6
+ export interface CompilerContext {
7
+ readonly filename: string
8
+ readonly factory: typeof ts.factory
9
+ addRuntimeImport(name: string): void
10
+ /**
11
+ * Create a reference to a runtime helper in generated code. When the source
12
+ * binds the same name, the compiler imports the helper under an alias and
13
+ * this returns the aliased identifier, so plugin-generated calls never
14
+ * collide with user bindings.
15
+ */
16
+ helperRef(name: string): ts.Identifier
17
+ }
18
+
19
+ export type AnalyzeContext = CompilerContext
20
+ export type TransformContext = CompilerContext
21
+
22
+ export interface CompilerPlugin {
23
+ readonly name: string
24
+ analyze?: (program: Program, context: AnalyzeContext) => void
25
+ transform?: {
26
+ program?: (program: Program, context: TransformContext) => Program | undefined
27
+ node?: (node: ASTNode, context: TransformContext) => ASTNode | null | undefined
28
+ }
29
+ /** @deprecated Use transform.node for new plugins. */
30
+ transformNode?: (node: ASTNode, context: TransformContext) => ASTNode | null | undefined
31
+ }
32
+
33
+ export interface CompilerOptions {
34
+ plugins?: readonly CompilerPlugin[]
35
+ }
36
+
37
+ export interface CompileOptions extends CompilerOptions {
38
+ filename?: string
39
+ }
40
+
41
+ export interface VobsSourceMap {
42
+ readonly version: 3
43
+ readonly file: string
44
+ readonly sources: string[]
45
+ readonly sourcesContent: string[]
46
+ readonly names: string[]
47
+ readonly mappings: string
48
+ }
49
+
50
+ export interface CompileResult {
51
+ readonly code: string
52
+ readonly map: VobsSourceMap
53
+ readonly diagnostics: readonly CompilerDiagnostic[]
54
+ }
55
+
56
+ export interface CompilerDiagnostic {
57
+ readonly code: string
58
+ readonly severity: 'error' | 'warning'
59
+ readonly message: string
60
+ readonly location: {
61
+ readonly file: string
62
+ readonly line: number
63
+ readonly column: number
64
+ }
65
+ readonly codeFrame?: string
66
+ readonly fix?: string
67
+ }
68
+
69
+ export interface VobsCompiler {
70
+ compile(code: string, options?: CompileOptions): string
71
+ compileWithSourceMap(code: string, options?: CompileOptions): CompileResult
72
+ }