@softize/opus 8.6.6
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/CHANGELOG.md +1616 -0
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/bin/cli.mjs +528 -0
- package/bin/lib/check.mjs +307 -0
- package/bin/lib/components.mjs +151 -0
- package/bin/lib/create.mjs +208 -0
- package/bin/lib/db-check-runner.mjs +86 -0
- package/bin/lib/db-migrate-runner.mjs +89 -0
- package/bin/lib/db-scaffold-runner.mjs +84 -0
- package/bin/lib/db.mjs +261 -0
- package/bin/lib/docs-include.mjs +48 -0
- package/bin/lib/gen-dicts.mjs +134 -0
- package/bin/lib/gen-docs.mjs +288 -0
- package/bin/lib/gen-manifest.mjs +102 -0
- package/bin/lib/gen-openapi.mjs +195 -0
- package/bin/lib/gen-runner.mjs +472 -0
- package/bin/lib/gen-stubs.mjs +463 -0
- package/bin/lib/gen.mjs +311 -0
- package/bin/lib/init.mjs +514 -0
- package/bin/lib/introspect.mjs +107 -0
- package/bin/lib/mcp.mjs +85 -0
- package/bin/lib/postinstall.mjs +56 -0
- package/docs/chat-event-protocol.md +85 -0
- package/docs/code-style.md +16 -0
- package/docs/data-layer.md +246 -0
- package/docs/ownership-vs-shadcn-lock.md +102 -0
- package/docs/protocol.md +2053 -0
- package/docs/releasing.md +110 -0
- package/docs/shellnav.md +131 -0
- package/package.json +338 -0
- package/registry/hooks/hooks.json +26 -0
- package/registry/hooks/link-memory-on-start.mjs +46 -0
- package/registry/hooks/opus-check-on-stop.mjs +114 -0
- package/registry/skills/create-action/SKILL.md +49 -0
- package/registry/skills/create-action/scaffold.mjs +122 -0
- package/registry/templates/app/_gitignore +3 -0
- package/registry/templates/app/_npmrc +1 -0
- package/registry/templates/app/_opus/_gitignore +5 -0
- package/registry/templates/app/_prettierrc.json +6 -0
- package/registry/templates/app/index.html +13 -0
- package/registry/templates/app/opus.config.ts +16 -0
- package/registry/templates/app/package.json +43 -0
- package/registry/templates/app/pnpm-workspace.yaml +11 -0
- package/registry/templates/app/public/favicon.svg +4 -0
- package/registry/templates/app/src/App.tsx +37 -0
- package/registry/templates/app/src/domains/tasks/actions/list.test.ts +34 -0
- package/registry/templates/app/src/domains/tasks/actions/list.ts +33 -0
- package/registry/templates/app/src/domains/tasks/index.ts +13 -0
- package/registry/templates/app/src/index.css +18 -0
- package/registry/templates/app/src/main.tsx +25 -0
- package/registry/templates/app/tsconfig.json +20 -0
- package/registry/templates/app/vite.config.ts +46 -0
- package/registry/templates/monorepo/_gitignore +3 -0
- package/registry/templates/monorepo/_npmrc +1 -0
- package/registry/templates/monorepo/package.json +9 -0
- package/registry/templates/monorepo/pnpm-workspace.yaml +14 -0
- package/src/ai/ask.ts +64 -0
- package/src/ai/drivers/anthropic.ts +309 -0
- package/src/ai/index.ts +17 -0
- package/src/audit/drivers/console.ts +117 -0
- package/src/audit/drivers/pg.ts +172 -0
- package/src/audit/index.ts +51 -0
- package/src/auth/drivers/better-auth.ts +103 -0
- package/src/auth/drivers/jwt.ts +188 -0
- package/src/auth/index.ts +9 -0
- package/src/client/drivers/fetch.ts +202 -0
- package/src/client/index.ts +22 -0
- package/src/core/actions.ts +110 -0
- package/src/core/audit.ts +239 -0
- package/src/core/contracts.ts +137 -0
- package/src/core/domain.ts +310 -0
- package/src/core/errors.ts +181 -0
- package/src/core/index.ts +174 -0
- package/src/core/logical-type.ts +31 -0
- package/src/core/reactions.ts +81 -0
- package/src/core/runtime.ts +1167 -0
- package/src/core/schedules.ts +41 -0
- package/src/core/types.ts +1356 -0
- package/src/data/drivers/kysely.ts +389 -0
- package/src/data/index.ts +10 -0
- package/src/data/readonly-pool.ts +160 -0
- package/src/dsl/eval.ts +136 -0
- package/src/dsl/index.ts +29 -0
- package/src/dsl/kysely.ts +230 -0
- package/src/dsl/loads.ts +123 -0
- package/src/dsl/parser.ts +423 -0
- package/src/dsl/types.ts +113 -0
- package/src/events/drivers/mitt.ts +70 -0
- package/src/events/index.ts +9 -0
- package/src/log/drivers/pino.ts +57 -0
- package/src/log/index.ts +9 -0
- package/src/mcp/index.ts +62 -0
- package/src/queue/drivers/bullmq.ts +190 -0
- package/src/queue/index.ts +9 -0
- package/src/scheduler/drivers/node-cron.ts +93 -0
- package/src/scheduler/every.ts +45 -0
- package/src/scheduler/index.ts +9 -0
- package/src/schema/drivers/zod.ts +765 -0
- package/src/schema/entity.ts +439 -0
- package/src/schema/format/locale.ts +144 -0
- package/src/schema/index.ts +65 -0
- package/src/schema/openapi.ts +302 -0
- package/src/schema/scaffold.ts +160 -0
- package/src/server/drivers/fastify.ts +224 -0
- package/src/server/drivers/node.ts +386 -0
- package/src/server/index.ts +142 -0
- package/src/storage/drivers/fs.ts +90 -0
- package/src/storage/drivers/s3.ts +117 -0
- package/src/storage/index.ts +27 -0
- package/src/testing/fake.ts +298 -0
- package/src/testing/index.ts +324 -0
- package/src/ui/components/patterns/action-form-card.tsx +48 -0
- package/src/ui/components/patterns/action-list-dialog.tsx +93 -0
- package/src/ui/components/patterns/app-shell.tsx +227 -0
- package/src/ui/components/patterns/confirm.tsx +226 -0
- package/src/ui/components/patterns/data-state.tsx +75 -0
- package/src/ui/components/patterns/form-dialog.tsx +64 -0
- package/src/ui/components/patterns/form.tsx +584 -0
- package/src/ui/components/patterns/list.tsx +1488 -0
- package/src/ui/components/patterns/page.tsx +46 -0
- package/src/ui/components/patterns/section-shell.tsx +246 -0
- package/src/ui/components/patterns/shell-nav.tsx +150 -0
- package/src/ui/components/patterns/sidebar.tsx +89 -0
- package/src/ui/components/patterns/split.tsx +93 -0
- package/src/ui/components/patterns/trigger.tsx +196 -0
- package/src/ui/components/patterns/view.tsx +84 -0
- package/src/ui/components/primitives/accordion.tsx +64 -0
- package/src/ui/components/primitives/alert-dialog.tsx +190 -0
- package/src/ui/components/primitives/alert.tsx +116 -0
- package/src/ui/components/primitives/aspect-ratio.tsx +9 -0
- package/src/ui/components/primitives/avatar.tsx +107 -0
- package/src/ui/components/primitives/badge.tsx +37 -0
- package/src/ui/components/primitives/breadcrumb.tsx +109 -0
- package/src/ui/components/primitives/button-group.tsx +83 -0
- package/src/ui/components/primitives/button.tsx +102 -0
- package/src/ui/components/primitives/calendar.tsx +218 -0
- package/src/ui/components/primitives/card.tsx +56 -0
- package/src/ui/components/primitives/carousel.tsx +239 -0
- package/src/ui/components/primitives/chat.tsx +407 -0
- package/src/ui/components/primitives/checkbox.tsx +30 -0
- package/src/ui/components/primitives/collapsible.tsx +31 -0
- package/src/ui/components/primitives/command.tsx +182 -0
- package/src/ui/components/primitives/composer.tsx +121 -0
- package/src/ui/components/primitives/copyable.tsx +50 -0
- package/src/ui/components/primitives/dialog.tsx +147 -0
- package/src/ui/components/primitives/drawer.tsx +141 -0
- package/src/ui/components/primitives/empty.tsx +104 -0
- package/src/ui/components/primitives/field.tsx +246 -0
- package/src/ui/components/primitives/icon-picker.tsx +180 -0
- package/src/ui/components/primitives/input-group.tsx +168 -0
- package/src/ui/components/primitives/input-otp.tsx +75 -0
- package/src/ui/components/primitives/input.tsx +72 -0
- package/src/ui/components/primitives/item.tsx +193 -0
- package/src/ui/components/primitives/kbd.tsx +28 -0
- package/src/ui/components/primitives/label.tsx +22 -0
- package/src/ui/components/primitives/markdown.tsx +35 -0
- package/src/ui/components/primitives/menu.tsx +255 -0
- package/src/ui/components/primitives/pagination.tsx +127 -0
- package/src/ui/components/primitives/popover.tsx +87 -0
- package/src/ui/components/primitives/progress.tsx +29 -0
- package/src/ui/components/primitives/radio-group.tsx +43 -0
- package/src/ui/components/primitives/resizable.tsx +51 -0
- package/src/ui/components/primitives/scroll-area.tsx +56 -0
- package/src/ui/components/primitives/select.tsx +479 -0
- package/src/ui/components/primitives/separator.tsx +26 -0
- package/src/ui/components/primitives/skeleton.tsx +13 -0
- package/src/ui/components/primitives/slider.tsx +61 -0
- package/src/ui/components/primitives/sonner.tsx +46 -0
- package/src/ui/components/primitives/spinner.tsx +29 -0
- package/src/ui/components/primitives/switch.tsx +33 -0
- package/src/ui/components/primitives/table.tsx +114 -0
- package/src/ui/components/primitives/tabs.tsx +104 -0
- package/src/ui/components/primitives/textarea.tsx +18 -0
- package/src/ui/components/primitives/toggle-group.tsx +81 -0
- package/src/ui/components/primitives/toggle.tsx +45 -0
- package/src/ui/components/primitives/tooltip.tsx +55 -0
- package/src/ui/components/primitives/truncate.tsx +49 -0
- package/src/ui/docs/DocBrowser.tsx +90 -0
- package/src/ui/docs/changelog.tsx +80 -0
- package/src/ui/docs/content/accordion.md +86 -0
- package/src/ui/docs/content/action-form-card.md +24 -0
- package/src/ui/docs/content/action-form-dialog.md +30 -0
- package/src/ui/docs/content/action-form.md +125 -0
- package/src/ui/docs/content/action-list-dialog.md +68 -0
- package/src/ui/docs/content/action-list.md +194 -0
- package/src/ui/docs/content/action-trigger.md +72 -0
- package/src/ui/docs/content/action-view.md +47 -0
- package/src/ui/docs/content/actions.md +138 -0
- package/src/ui/docs/content/ai.md +112 -0
- package/src/ui/docs/content/alert-dialog.md +73 -0
- package/src/ui/docs/content/alert.md +69 -0
- package/src/ui/docs/content/app-shell.md +155 -0
- package/src/ui/docs/content/aspect-ratio.md +66 -0
- package/src/ui/docs/content/audit.md +84 -0
- package/src/ui/docs/content/auth.md +70 -0
- package/src/ui/docs/content/avatar.md +94 -0
- package/src/ui/docs/content/badge.md +48 -0
- package/src/ui/docs/content/breadcrumb.md +87 -0
- package/src/ui/docs/content/button-group.md +71 -0
- package/src/ui/docs/content/button.md +60 -0
- package/src/ui/docs/content/calendar.md +62 -0
- package/src/ui/docs/content/card.md +49 -0
- package/src/ui/docs/content/carousel.md +85 -0
- package/src/ui/docs/content/chat.md +69 -0
- package/src/ui/docs/content/checkbox.md +75 -0
- package/src/ui/docs/content/cli.md +58 -0
- package/src/ui/docs/content/collapsible.md +64 -0
- package/src/ui/docs/content/command.md +56 -0
- package/src/ui/docs/content/composer.md +50 -0
- package/src/ui/docs/content/confirm.md +120 -0
- package/src/ui/docs/content/copyable.md +30 -0
- package/src/ui/docs/content/customization.md +110 -0
- package/src/ui/docs/content/cycle.md +34 -0
- package/src/ui/docs/content/data-state.md +47 -0
- package/src/ui/docs/content/data.md +99 -0
- package/src/ui/docs/content/dialog.md +60 -0
- package/src/ui/docs/content/drawer.md +55 -0
- package/src/ui/docs/content/empty.md +66 -0
- package/src/ui/docs/content/events.md +61 -0
- package/src/ui/docs/content/field.md +58 -0
- package/src/ui/docs/content/getting-started.md +109 -0
- package/src/ui/docs/content/icon-picker.md +51 -0
- package/src/ui/docs/content/input-group.md +78 -0
- package/src/ui/docs/content/input-otp.md +72 -0
- package/src/ui/docs/content/input.md +78 -0
- package/src/ui/docs/content/item.md +84 -0
- package/src/ui/docs/content/kbd.md +62 -0
- package/src/ui/docs/content/label.md +32 -0
- package/src/ui/docs/content/log.md +55 -0
- package/src/ui/docs/content/markdown.md +41 -0
- package/src/ui/docs/content/mcp.md +44 -0
- package/src/ui/docs/content/menu.md +114 -0
- package/src/ui/docs/content/microcopy.md +83 -0
- package/src/ui/docs/content/page.md +34 -0
- package/src/ui/docs/content/pagination.md +99 -0
- package/src/ui/docs/content/popover.md +49 -0
- package/src/ui/docs/content/progress.md +69 -0
- package/src/ui/docs/content/queue.md +62 -0
- package/src/ui/docs/content/radio-group.md +77 -0
- package/src/ui/docs/content/resizable.md +86 -0
- package/src/ui/docs/content/router.md +56 -0
- package/src/ui/docs/content/runtime.md +77 -0
- package/src/ui/docs/content/scheduler.md +66 -0
- package/src/ui/docs/content/scroll-area.md +89 -0
- package/src/ui/docs/content/section-shell.md +121 -0
- package/src/ui/docs/content/select.md +342 -0
- package/src/ui/docs/content/separator.md +33 -0
- package/src/ui/docs/content/sidebar.md +38 -0
- package/src/ui/docs/content/skeleton.md +34 -0
- package/src/ui/docs/content/slider.md +64 -0
- package/src/ui/docs/content/spinner.md +37 -0
- package/src/ui/docs/content/split.md +33 -0
- package/src/ui/docs/content/storage.md +69 -0
- package/src/ui/docs/content/switch.md +69 -0
- package/src/ui/docs/content/table.md +102 -0
- package/src/ui/docs/content/tabs.md +94 -0
- package/src/ui/docs/content/testing.md +89 -0
- package/src/ui/docs/content/textarea.md +30 -0
- package/src/ui/docs/content/toast.md +67 -0
- package/src/ui/docs/content/toggle-group.md +81 -0
- package/src/ui/docs/content/toggle.md +72 -0
- package/src/ui/docs/content/tokens.md +171 -0
- package/src/ui/docs/content/tooltip.md +50 -0
- package/src/ui/docs/content/truncate.md +37 -0
- package/src/ui/docs/content/ui.md +40 -0
- package/src/ui/docs/content/upgrading.md +48 -0
- package/src/ui/docs/doc-client.tsx +214 -0
- package/src/ui/docs/doc.tsx +301 -0
- package/src/ui/docs/folder.tsx +149 -0
- package/src/ui/docs/index.ts +21 -0
- package/src/ui/docs/markdown.tsx +130 -0
- package/src/ui/docs/md-raw.d.ts +4 -0
- package/src/ui/docs/plugin.ts +104 -0
- package/src/ui/docs/registry.tsx +424 -0
- package/src/ui/docs/standalone.tsx +107 -0
- package/src/ui/drivers/react.tsx +627 -0
- package/src/ui/index.ts +92 -0
- package/src/ui/lib/cn.ts +10 -0
- package/src/ui/lib/zod-pt-br.ts +38 -0
- package/src/ui/meta.ts +412 -0
- package/src/ui/react.tsx +235 -0
- package/src/ui/router.ts +96 -0
- package/src/ui/theme.css +234 -0
- package/src/vite/design.ts +652 -0
- package/src/vite/index.ts +8 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @softize/opus/dsl — Tokenizer + parser de expressões.
|
|
3
|
+
*
|
|
4
|
+
* Gramática (descendente recursiva, precedência: NOT > comp > AND > OR):
|
|
5
|
+
*
|
|
6
|
+
* expr = orExpr
|
|
7
|
+
* orExpr = andExpr ('OR' andExpr)*
|
|
8
|
+
* andExpr = notExpr ('AND' notExpr)*
|
|
9
|
+
* notExpr = 'NOT' notExpr | compExpr
|
|
10
|
+
* compExpr = addExpr (compOp compExpr)?
|
|
11
|
+
* compOp = '==' | '!=' | '<' | '<=' | '>' | '>=' |
|
|
12
|
+
* ('NOT')? 'IN' | ('NOT')? 'BETWEEN' |
|
|
13
|
+
* ('NOT')? ('I')? 'LIKE' | 'IS' ('NOT')? 'NULL'
|
|
14
|
+
* addExpr = mulExpr (('+'|'-') mulExpr)*
|
|
15
|
+
* mulExpr = unary (('*'|'/') unary)*
|
|
16
|
+
* unary = '-' unary | primary
|
|
17
|
+
* primary = literal | array | functionCall | identifier ('.' ident)* | '(' expr ')'
|
|
18
|
+
* array = '[' (expr (',' expr)*)? ']'
|
|
19
|
+
* functionCall= ident '(' (expr (',' expr)*)? ')'
|
|
20
|
+
* literal = STRING | NUMBER | 'true' | 'false' | 'null'
|
|
21
|
+
*
|
|
22
|
+
* Identifiers válidos: [a-zA-Z_][a-zA-Z0-9_]*. Mas NÃO podem ser keyword
|
|
23
|
+
* reservada (AND, OR, NOT, IN, BETWEEN, LIKE, ILIKE, IS, NULL, true, false).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { AstNode } from './types.ts'
|
|
27
|
+
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Tokens
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
type TokenType =
|
|
33
|
+
| 'NUMBER'
|
|
34
|
+
| 'STRING'
|
|
35
|
+
| 'IDENT'
|
|
36
|
+
| 'KEYWORD'
|
|
37
|
+
| 'OP'
|
|
38
|
+
| 'PUNCT'
|
|
39
|
+
| 'EOF'
|
|
40
|
+
|
|
41
|
+
interface Token {
|
|
42
|
+
type: TokenType
|
|
43
|
+
value: string
|
|
44
|
+
pos: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const KEYWORDS = new Set([
|
|
48
|
+
'AND',
|
|
49
|
+
'OR',
|
|
50
|
+
'NOT',
|
|
51
|
+
'IN',
|
|
52
|
+
'BETWEEN',
|
|
53
|
+
'LIKE',
|
|
54
|
+
'ILIKE',
|
|
55
|
+
'IS',
|
|
56
|
+
'NULL',
|
|
57
|
+
'TRUE',
|
|
58
|
+
'FALSE',
|
|
59
|
+
])
|
|
60
|
+
|
|
61
|
+
const MULTI_CHAR_OPS = ['==', '!=', '<=', '>='] as const
|
|
62
|
+
const SINGLE_CHAR_OPS = ['<', '>', '+', '-', '*', '/'] as const
|
|
63
|
+
const PUNCTS = ['(', ')', '[', ']', ',', '.'] as const
|
|
64
|
+
|
|
65
|
+
function tokenize(src: string): Token[] {
|
|
66
|
+
const tokens: Token[] = []
|
|
67
|
+
let i = 0
|
|
68
|
+
while (i < src.length) {
|
|
69
|
+
const c = src[i]!
|
|
70
|
+
// whitespace
|
|
71
|
+
if (c === ' ' || c === '\t' || c === '\n' || c === '\r') {
|
|
72
|
+
i += 1
|
|
73
|
+
continue
|
|
74
|
+
}
|
|
75
|
+
const startPos = i
|
|
76
|
+
|
|
77
|
+
// string literals (single or double quote)
|
|
78
|
+
if (c === '"' || c === "'") {
|
|
79
|
+
const quote = c
|
|
80
|
+
i += 1
|
|
81
|
+
let val = ''
|
|
82
|
+
while (i < src.length && src[i] !== quote) {
|
|
83
|
+
if (src[i] === '\\' && i + 1 < src.length) {
|
|
84
|
+
val += src[i + 1]
|
|
85
|
+
i += 2
|
|
86
|
+
} else {
|
|
87
|
+
val += src[i]!
|
|
88
|
+
i += 1
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (i >= src.length) {
|
|
92
|
+
throw new Error(`DSL parse error: unterminated string at ${startPos}`)
|
|
93
|
+
}
|
|
94
|
+
i += 1 // skip closing quote
|
|
95
|
+
tokens.push({ type: 'STRING', value: val, pos: startPos })
|
|
96
|
+
continue
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// numbers
|
|
100
|
+
if (c >= '0' && c <= '9') {
|
|
101
|
+
let val = ''
|
|
102
|
+
while (i < src.length && /[0-9.]/.test(src[i]!)) {
|
|
103
|
+
val += src[i]!
|
|
104
|
+
i += 1
|
|
105
|
+
}
|
|
106
|
+
tokens.push({ type: 'NUMBER', value: val, pos: startPos })
|
|
107
|
+
continue
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// multi-char operators
|
|
111
|
+
let matched = false
|
|
112
|
+
for (const op of MULTI_CHAR_OPS) {
|
|
113
|
+
if (src.startsWith(op, i)) {
|
|
114
|
+
tokens.push({ type: 'OP', value: op, pos: startPos })
|
|
115
|
+
i += op.length
|
|
116
|
+
matched = true
|
|
117
|
+
break
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (matched) continue
|
|
121
|
+
|
|
122
|
+
// single-char operators
|
|
123
|
+
if (SINGLE_CHAR_OPS.includes(c as (typeof SINGLE_CHAR_OPS)[number])) {
|
|
124
|
+
tokens.push({ type: 'OP', value: c, pos: startPos })
|
|
125
|
+
i += 1
|
|
126
|
+
continue
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// punctuation
|
|
130
|
+
if (PUNCTS.includes(c as (typeof PUNCTS)[number])) {
|
|
131
|
+
tokens.push({ type: 'PUNCT', value: c, pos: startPos })
|
|
132
|
+
i += 1
|
|
133
|
+
continue
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// identifiers / keywords
|
|
137
|
+
if (/[a-zA-Z_]/.test(c)) {
|
|
138
|
+
let val = ''
|
|
139
|
+
while (i < src.length && /[a-zA-Z0-9_]/.test(src[i]!)) {
|
|
140
|
+
val += src[i]!
|
|
141
|
+
i += 1
|
|
142
|
+
}
|
|
143
|
+
const upper = val.toUpperCase()
|
|
144
|
+
if (KEYWORDS.has(upper)) {
|
|
145
|
+
tokens.push({ type: 'KEYWORD', value: upper, pos: startPos })
|
|
146
|
+
} else {
|
|
147
|
+
tokens.push({ type: 'IDENT', value: val, pos: startPos })
|
|
148
|
+
}
|
|
149
|
+
continue
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
throw new Error(
|
|
153
|
+
`DSL parse error: unexpected character '${c}' at position ${i}`,
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
tokens.push({ type: 'EOF', value: '', pos: src.length })
|
|
157
|
+
return tokens
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// =============================================================================
|
|
161
|
+
// Parser (recursive descent)
|
|
162
|
+
// =============================================================================
|
|
163
|
+
|
|
164
|
+
class Parser {
|
|
165
|
+
private pos = 0
|
|
166
|
+
constructor(private tokens: Token[]) {}
|
|
167
|
+
|
|
168
|
+
private peek(offset = 0): Token {
|
|
169
|
+
return this.tokens[this.pos + offset]!
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private consume(): Token {
|
|
173
|
+
return this.tokens[this.pos++]!
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private match(type: TokenType, value?: string): boolean {
|
|
177
|
+
const t = this.peek()
|
|
178
|
+
if (t.type !== type) return false
|
|
179
|
+
if (value !== undefined && t.value !== value) return false
|
|
180
|
+
return true
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private expect(type: TokenType, value?: string): Token {
|
|
184
|
+
if (!this.match(type, value)) {
|
|
185
|
+
const t = this.peek()
|
|
186
|
+
throw new Error(
|
|
187
|
+
`DSL parse error: expected ${value ?? type}, got '${t.value}' at ${t.pos}`,
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
return this.consume()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
parse(): AstNode {
|
|
194
|
+
const expr = this.orExpr()
|
|
195
|
+
this.expect('EOF')
|
|
196
|
+
return expr
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private orExpr(): AstNode {
|
|
200
|
+
let left = this.andExpr()
|
|
201
|
+
while (this.match('KEYWORD', 'OR')) {
|
|
202
|
+
this.consume()
|
|
203
|
+
const right = this.andExpr()
|
|
204
|
+
left = { kind: 'binary', op: 'OR', left, right }
|
|
205
|
+
}
|
|
206
|
+
return left
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private andExpr(): AstNode {
|
|
210
|
+
let left = this.notExpr()
|
|
211
|
+
while (this.match('KEYWORD', 'AND')) {
|
|
212
|
+
this.consume()
|
|
213
|
+
const right = this.notExpr()
|
|
214
|
+
left = { kind: 'binary', op: 'AND', left, right }
|
|
215
|
+
}
|
|
216
|
+
return left
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private notExpr(): AstNode {
|
|
220
|
+
if (this.match('KEYWORD', 'NOT')) {
|
|
221
|
+
this.consume()
|
|
222
|
+
const operand = this.notExpr()
|
|
223
|
+
return { kind: 'unary', op: 'NOT', operand }
|
|
224
|
+
}
|
|
225
|
+
return this.compExpr()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private compExpr(): AstNode {
|
|
229
|
+
const left = this.addExpr()
|
|
230
|
+
|
|
231
|
+
// Detecta operadores de comparação
|
|
232
|
+
// ==, !=, <, <=, >, >=
|
|
233
|
+
if (
|
|
234
|
+
this.match('OP', '==') ||
|
|
235
|
+
this.match('OP', '!=') ||
|
|
236
|
+
this.match('OP', '<') ||
|
|
237
|
+
this.match('OP', '<=') ||
|
|
238
|
+
this.match('OP', '>') ||
|
|
239
|
+
this.match('OP', '>=')
|
|
240
|
+
) {
|
|
241
|
+
const op = this.consume().value as
|
|
242
|
+
| '=='
|
|
243
|
+
| '!='
|
|
244
|
+
| '<'
|
|
245
|
+
| '<='
|
|
246
|
+
| '>'
|
|
247
|
+
| '>='
|
|
248
|
+
const right = this.addExpr()
|
|
249
|
+
return { kind: 'binary', op, left, right }
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// IS NULL / IS NOT NULL
|
|
253
|
+
if (this.match('KEYWORD', 'IS')) {
|
|
254
|
+
this.consume()
|
|
255
|
+
let negated = false
|
|
256
|
+
if (this.match('KEYWORD', 'NOT')) {
|
|
257
|
+
this.consume()
|
|
258
|
+
negated = true
|
|
259
|
+
}
|
|
260
|
+
this.expect('KEYWORD', 'NULL')
|
|
261
|
+
return { kind: 'isNull', negated, subject: left }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// NOT IN / NOT BETWEEN / NOT LIKE / NOT ILIKE
|
|
265
|
+
let negated = false
|
|
266
|
+
if (this.match('KEYWORD', 'NOT')) {
|
|
267
|
+
const save = this.pos
|
|
268
|
+
this.consume()
|
|
269
|
+
if (
|
|
270
|
+
this.match('KEYWORD', 'IN') ||
|
|
271
|
+
this.match('KEYWORD', 'BETWEEN') ||
|
|
272
|
+
this.match('KEYWORD', 'LIKE') ||
|
|
273
|
+
this.match('KEYWORD', 'ILIKE')
|
|
274
|
+
) {
|
|
275
|
+
negated = true
|
|
276
|
+
} else {
|
|
277
|
+
// não era NOT-de-comparison; foi unary NOT após primary? não é gramaticalmente
|
|
278
|
+
// possível aqui. Restaura.
|
|
279
|
+
this.pos = save
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (this.match('KEYWORD', 'IN')) {
|
|
284
|
+
this.consume()
|
|
285
|
+
const values = this.primary()
|
|
286
|
+
return { kind: 'in', negated, left, values }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (this.match('KEYWORD', 'BETWEEN')) {
|
|
290
|
+
this.consume()
|
|
291
|
+
const low = this.addExpr()
|
|
292
|
+
this.expect('KEYWORD', 'AND')
|
|
293
|
+
const high = this.addExpr()
|
|
294
|
+
return { kind: 'between', negated, subject: left, low, high }
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (this.match('KEYWORD', 'LIKE') || this.match('KEYWORD', 'ILIKE')) {
|
|
298
|
+
const tok = this.consume()
|
|
299
|
+
const caseInsensitive = tok.value === 'ILIKE'
|
|
300
|
+
const pattern = this.addExpr()
|
|
301
|
+
return { kind: 'like', caseInsensitive, negated, subject: left, pattern }
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return left
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private addExpr(): AstNode {
|
|
308
|
+
let left = this.mulExpr()
|
|
309
|
+
while (this.match('OP', '+') || this.match('OP', '-')) {
|
|
310
|
+
const op = this.consume().value as '+' | '-'
|
|
311
|
+
const right = this.mulExpr()
|
|
312
|
+
left = { kind: 'binary', op, left, right }
|
|
313
|
+
}
|
|
314
|
+
return left
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private mulExpr(): AstNode {
|
|
318
|
+
let left = this.unary()
|
|
319
|
+
while (this.match('OP', '*') || this.match('OP', '/')) {
|
|
320
|
+
const op = this.consume().value as '*' | '/'
|
|
321
|
+
const right = this.unary()
|
|
322
|
+
left = { kind: 'binary', op, left, right }
|
|
323
|
+
}
|
|
324
|
+
return left
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private unary(): AstNode {
|
|
328
|
+
if (this.match('OP', '-')) {
|
|
329
|
+
this.consume()
|
|
330
|
+
return { kind: 'unary', op: '-', operand: this.unary() }
|
|
331
|
+
}
|
|
332
|
+
return this.primary()
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private primary(): AstNode {
|
|
336
|
+
// STRING
|
|
337
|
+
if (this.match('STRING')) {
|
|
338
|
+
const t = this.consume()
|
|
339
|
+
return { kind: 'literal', value: t.value }
|
|
340
|
+
}
|
|
341
|
+
// NUMBER
|
|
342
|
+
if (this.match('NUMBER')) {
|
|
343
|
+
const t = this.consume()
|
|
344
|
+
const n = Number(t.value)
|
|
345
|
+
if (Number.isNaN(n)) {
|
|
346
|
+
throw new Error(`DSL parse error: invalid number '${t.value}'`)
|
|
347
|
+
}
|
|
348
|
+
return { kind: 'literal', value: n }
|
|
349
|
+
}
|
|
350
|
+
// booleans / null
|
|
351
|
+
if (this.match('KEYWORD', 'TRUE')) {
|
|
352
|
+
this.consume()
|
|
353
|
+
return { kind: 'literal', value: true }
|
|
354
|
+
}
|
|
355
|
+
if (this.match('KEYWORD', 'FALSE')) {
|
|
356
|
+
this.consume()
|
|
357
|
+
return { kind: 'literal', value: false }
|
|
358
|
+
}
|
|
359
|
+
if (this.match('KEYWORD', 'NULL')) {
|
|
360
|
+
this.consume()
|
|
361
|
+
return { kind: 'literal', value: null }
|
|
362
|
+
}
|
|
363
|
+
// array
|
|
364
|
+
if (this.match('PUNCT', '[')) {
|
|
365
|
+
this.consume()
|
|
366
|
+
const items: AstNode[] = []
|
|
367
|
+
if (!this.match('PUNCT', ']')) {
|
|
368
|
+
items.push(this.orExpr())
|
|
369
|
+
while (this.match('PUNCT', ',')) {
|
|
370
|
+
this.consume()
|
|
371
|
+
items.push(this.orExpr())
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
this.expect('PUNCT', ']')
|
|
375
|
+
return { kind: 'array', items }
|
|
376
|
+
}
|
|
377
|
+
// parenthesized
|
|
378
|
+
if (this.match('PUNCT', '(')) {
|
|
379
|
+
this.consume()
|
|
380
|
+
const inner = this.orExpr()
|
|
381
|
+
this.expect('PUNCT', ')')
|
|
382
|
+
return inner
|
|
383
|
+
}
|
|
384
|
+
// identifier / function call / member access
|
|
385
|
+
if (this.match('IDENT')) {
|
|
386
|
+
const name = this.consume().value
|
|
387
|
+
// function call?
|
|
388
|
+
if (this.match('PUNCT', '(')) {
|
|
389
|
+
this.consume()
|
|
390
|
+
const args: AstNode[] = []
|
|
391
|
+
if (!this.match('PUNCT', ')')) {
|
|
392
|
+
args.push(this.orExpr())
|
|
393
|
+
while (this.match('PUNCT', ',')) {
|
|
394
|
+
this.consume()
|
|
395
|
+
args.push(this.orExpr())
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
this.expect('PUNCT', ')')
|
|
399
|
+
return { kind: 'call', name: name.toUpperCase(), args }
|
|
400
|
+
}
|
|
401
|
+
// member access (a.b.c)
|
|
402
|
+
let node: AstNode = { kind: 'identifier', name }
|
|
403
|
+
while (this.match('PUNCT', '.')) {
|
|
404
|
+
this.consume()
|
|
405
|
+
const prop = this.expect('IDENT').value
|
|
406
|
+
node = { kind: 'member', object: node, property: prop }
|
|
407
|
+
}
|
|
408
|
+
return node
|
|
409
|
+
}
|
|
410
|
+
const t = this.peek()
|
|
411
|
+
throw new Error(
|
|
412
|
+
`DSL parse error: unexpected token '${t.value}' at ${t.pos}`,
|
|
413
|
+
)
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// =============================================================================
|
|
418
|
+
// Public
|
|
419
|
+
// =============================================================================
|
|
420
|
+
|
|
421
|
+
export function parseExpression(src: string): AstNode {
|
|
422
|
+
return new Parser(tokenize(src)).parse()
|
|
423
|
+
}
|
package/src/dsl/types.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @softize/opus/dsl — AST de expressões DSL.
|
|
3
|
+
*
|
|
4
|
+
* Mesma AST consumida por 3 compilers:
|
|
5
|
+
* - evalExpression() — runtime boolean evaluation (autorize)
|
|
6
|
+
* - compileToKysely() — SQL where clause builder
|
|
7
|
+
* - compileToFilterTree() — UI filter builder (futuro)
|
|
8
|
+
*
|
|
9
|
+
* Inspirada em SQL + JS literals. Ver README do módulo pra gramática
|
|
10
|
+
* completa.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// AST nodes (discriminated union por `kind`)
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
export type AstNode =
|
|
18
|
+
| LiteralNode
|
|
19
|
+
| ArrayNode
|
|
20
|
+
| IdentifierNode
|
|
21
|
+
| MemberAccessNode
|
|
22
|
+
| UnaryOpNode
|
|
23
|
+
| BinaryOpNode
|
|
24
|
+
| InNode
|
|
25
|
+
| BetweenNode
|
|
26
|
+
| LikeNode
|
|
27
|
+
| IsNullNode
|
|
28
|
+
| FunctionCallNode
|
|
29
|
+
|
|
30
|
+
export interface LiteralNode {
|
|
31
|
+
kind: 'literal'
|
|
32
|
+
value: string | number | boolean | null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ArrayNode {
|
|
36
|
+
kind: 'array'
|
|
37
|
+
items: AstNode[]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface IdentifierNode {
|
|
41
|
+
kind: 'identifier'
|
|
42
|
+
name: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** `a.b.c` — encadeamento de access. */
|
|
46
|
+
export interface MemberAccessNode {
|
|
47
|
+
kind: 'member'
|
|
48
|
+
object: AstNode
|
|
49
|
+
property: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface UnaryOpNode {
|
|
53
|
+
kind: 'unary'
|
|
54
|
+
op: 'NOT' | '-'
|
|
55
|
+
operand: AstNode
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type BinaryOp =
|
|
59
|
+
| '=='
|
|
60
|
+
| '!='
|
|
61
|
+
| '<'
|
|
62
|
+
| '<='
|
|
63
|
+
| '>'
|
|
64
|
+
| '>='
|
|
65
|
+
| 'AND'
|
|
66
|
+
| 'OR'
|
|
67
|
+
| '+'
|
|
68
|
+
| '-'
|
|
69
|
+
| '*'
|
|
70
|
+
| '/'
|
|
71
|
+
|
|
72
|
+
export interface BinaryOpNode {
|
|
73
|
+
kind: 'binary'
|
|
74
|
+
op: BinaryOp
|
|
75
|
+
left: AstNode
|
|
76
|
+
right: AstNode
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** `x IN (a, b, c)` — array implícito do lado direito. */
|
|
80
|
+
export interface InNode {
|
|
81
|
+
kind: 'in'
|
|
82
|
+
negated: boolean
|
|
83
|
+
left: AstNode
|
|
84
|
+
values: AstNode // tipicamente ArrayNode
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface BetweenNode {
|
|
88
|
+
kind: 'between'
|
|
89
|
+
negated: boolean
|
|
90
|
+
subject: AstNode
|
|
91
|
+
low: AstNode
|
|
92
|
+
high: AstNode
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface LikeNode {
|
|
96
|
+
kind: 'like'
|
|
97
|
+
caseInsensitive: boolean // ILIKE
|
|
98
|
+
negated: boolean
|
|
99
|
+
subject: AstNode
|
|
100
|
+
pattern: AstNode
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface IsNullNode {
|
|
104
|
+
kind: 'isNull'
|
|
105
|
+
negated: boolean // IS NOT NULL
|
|
106
|
+
subject: AstNode
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface FunctionCallNode {
|
|
110
|
+
kind: 'call'
|
|
111
|
+
name: string // NOW, LOWER, COALESCE, etc
|
|
112
|
+
args: AstNode[]
|
|
113
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @softize/opus/events/mitt — in-process EventBus driver
|
|
3
|
+
*
|
|
4
|
+
* Wrappa `mitt` (200 bytes, zero-dep) implementando `EventBusAdapter`.
|
|
5
|
+
* Pra monolito / dev / testes. Distribuição cross-service usa
|
|
6
|
+
* `/redis` ou `/nats` (a virem).
|
|
7
|
+
*
|
|
8
|
+
* Pattern matching:
|
|
9
|
+
* - Nome literal: `subscribe('deal.archived', h)` recebe só esse evento.
|
|
10
|
+
* - Wildcard global: `subscribe('*', h)` recebe **todos** os eventos
|
|
11
|
+
* (mitt nativo). Útil pra audit secundário, analytics fan-out.
|
|
12
|
+
* - Padrões parciais (ex: `'crm.*'`) **não** suportados em v0 — exige
|
|
13
|
+
* wrapper customizado. Use `*` + filtro no handler quando preciso.
|
|
14
|
+
*
|
|
15
|
+
* Uso:
|
|
16
|
+
* import { mittEvents } from '@softize/opus/events/mitt'
|
|
17
|
+
*
|
|
18
|
+
* const bus = mittEvents()
|
|
19
|
+
* bus.subscribe('deal.archived', (event) => console.log(event))
|
|
20
|
+
* createRuntime({ eventBus: bus, ... })
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import mitt, { type Emitter } from 'mitt'
|
|
24
|
+
import type {
|
|
25
|
+
DomainEvent,
|
|
26
|
+
EventBusAdapter,
|
|
27
|
+
Unsubscribe,
|
|
28
|
+
} from '../../core/index.ts'
|
|
29
|
+
|
|
30
|
+
export interface MittEventsOptions {
|
|
31
|
+
/** Nome do adapter (default 'mitt'). */
|
|
32
|
+
name?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Map de tipos pra mitt: chave é o nome do evento, valor é `DomainEvent`.
|
|
37
|
+
* Usamos `Record<string, DomainEvent>` pra mitt aceitar qualquer string como
|
|
38
|
+
* type (não limita a um union literal).
|
|
39
|
+
*/
|
|
40
|
+
type EventMap = Record<string, DomainEvent>
|
|
41
|
+
|
|
42
|
+
export function mittEvents(options: MittEventsOptions = {}): EventBusAdapter {
|
|
43
|
+
const { name = 'mitt' } = options
|
|
44
|
+
const emitter: Emitter<EventMap> = mitt<EventMap>()
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
name,
|
|
48
|
+
kind: 'eventbus',
|
|
49
|
+
|
|
50
|
+
publish(event: DomainEvent) {
|
|
51
|
+
emitter.emit(event.type, event)
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
subscribe(pattern: string, listener: (event: DomainEvent) => void): Unsubscribe {
|
|
55
|
+
if (pattern === '*') {
|
|
56
|
+
const wildcardHandler = (_type: string | symbol, event: DomainEvent): void => {
|
|
57
|
+
listener(event)
|
|
58
|
+
}
|
|
59
|
+
emitter.on('*', wildcardHandler)
|
|
60
|
+
return () => emitter.off('*', wildcardHandler)
|
|
61
|
+
}
|
|
62
|
+
emitter.on(pattern, listener)
|
|
63
|
+
return () => emitter.off(pattern, listener)
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
healthCheck() {
|
|
67
|
+
return Promise.resolve({ ok: true })
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @softize/opus/events — shared helpers/types for event-bus drivers.
|
|
3
|
+
*
|
|
4
|
+
* Drivers (mitt, futuro: redis, nats) implementam EventBusAdapter do core.
|
|
5
|
+
* Espaço reservado pra helpers comuns (wildcard matcher universal,
|
|
6
|
+
* envelope normalization, etc).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export {}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @softize/opus/log/pino — Pino logger driver
|
|
3
|
+
*
|
|
4
|
+
* Adapta uma instância `pino.Logger` à interface `LoggerAdapter`.
|
|
5
|
+
*
|
|
6
|
+
* Pino assina `logger.info(obj, msg)` (objeto primeiro, mensagem depois);
|
|
7
|
+
* o LoggerAdapter assina `info(msg, meta?)`. Wrapper reordena.
|
|
8
|
+
*
|
|
9
|
+
* Uso:
|
|
10
|
+
* import pino from 'pino'
|
|
11
|
+
* import { pinoLogger } from '@softize/opus/log/pino'
|
|
12
|
+
*
|
|
13
|
+
* const logger = pino({ level: 'info' })
|
|
14
|
+
* createRuntime({ logger: pinoLogger({ logger }) })
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { LoggerAdapter } from '../../core/index.ts'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Subset de `pino.Logger` que precisamos. Permite passar qualquer logger
|
|
21
|
+
* pino-compatível (pino, pino-pretty, custom destination).
|
|
22
|
+
*/
|
|
23
|
+
export interface PinoCompatible {
|
|
24
|
+
trace(obj: object, msg: string): void
|
|
25
|
+
debug(obj: object, msg: string): void
|
|
26
|
+
info(obj: object, msg: string): void
|
|
27
|
+
warn(obj: object, msg: string): void
|
|
28
|
+
error(obj: object, msg: string): void
|
|
29
|
+
fatal(obj: object, msg: string): void
|
|
30
|
+
child(bindings: object): PinoCompatible
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface PinoLoggerOptions {
|
|
34
|
+
/** Instância pino (ou pino-compatível) já configurada. */
|
|
35
|
+
logger: PinoCompatible
|
|
36
|
+
|
|
37
|
+
/** Nome do adapter (default 'pino'). */
|
|
38
|
+
name?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function pinoLogger(options: PinoLoggerOptions): LoggerAdapter {
|
|
42
|
+
return makeAdapter(options.logger, options.name ?? 'pino')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function makeAdapter(logger: PinoCompatible, name: string): LoggerAdapter {
|
|
46
|
+
return {
|
|
47
|
+
name,
|
|
48
|
+
kind: 'logger',
|
|
49
|
+
trace: (msg, meta) => logger.trace(meta ?? {}, msg),
|
|
50
|
+
debug: (msg, meta) => logger.debug(meta ?? {}, msg),
|
|
51
|
+
info: (msg, meta) => logger.info(meta ?? {}, msg),
|
|
52
|
+
warn: (msg, meta) => logger.warn(meta ?? {}, msg),
|
|
53
|
+
error: (msg, meta) => logger.error(meta ?? {}, msg),
|
|
54
|
+
fatal: (msg, meta) => logger.fatal(meta ?? {}, msg),
|
|
55
|
+
child: (bindings) => makeAdapter(logger.child(bindings), name),
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/log/index.ts
ADDED