@telorun/assert 0.1.12 → 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/README.md CHANGED
@@ -1,7 +1,3 @@
1
- ---
2
- description: "Telo: YAML-driven execution engine for declarative backends with micro-kernel architecture and language-agnostic design"
3
- ---
4
-
5
1
  # ⚡ Telo
6
2
 
7
3
  Runtime for declarative backends.
@@ -11,6 +11,7 @@ interface ManifestAssertManifest {
11
11
  source: string;
12
12
  expect: {
13
13
  errors?: ExpectError[];
14
+ warnings?: ExpectError[];
14
15
  loadError?: string;
15
16
  };
16
17
  }
package/dist/manifest.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { DEFAULT_MANIFEST_FILENAME, Loader, StaticAnalyzer } from "@telorun/analyzer";
2
2
  import * as fs from "fs/promises";
3
3
  import * as path from "path";
4
- class LocalFileAdapter {
4
+ class LocalFileSource {
5
5
  supports(p) {
6
6
  return (p.startsWith("file://") ||
7
7
  p.startsWith("/") ||
@@ -52,7 +52,7 @@ export async function create(manifest, ctx) {
52
52
  const green = (t) => c("32", t);
53
53
  const dim = (t) => c("2", t);
54
54
  const name = manifest.metadata.name;
55
- const loader = new Loader([new LocalFileAdapter()]);
55
+ const loader = new Loader([new LocalFileSource()]);
56
56
  const analyzer = new StaticAnalyzer();
57
57
  const resolvedUrl = new URL(manifest.source, ctx.moduleContext.source).toString();
58
58
  let manifests;
@@ -87,7 +87,9 @@ export async function create(manifest, ctx) {
87
87
  }
88
88
  const diagnostics = analyzer.analyze(manifests);
89
89
  const errors = diagnostics.filter((d) => d.severity === 1); // DiagnosticSeverity.Error = 1
90
+ const warnings = diagnostics.filter((d) => d.severity === 2); // DiagnosticSeverity.Warning = 2
90
91
  const expectedErrors = manifest.expect.errors ?? [];
92
+ const expectedWarnings = manifest.expect.warnings ?? [];
91
93
  const failures = [];
92
94
  const matched = [];
93
95
  if (expectedErrors.length === 0) {
@@ -108,17 +110,34 @@ export async function create(manifest, ctx) {
108
110
  matched.push(`${expected.code ?? "*"}${expected.message ? ` (${expected.message})` : ""}`);
109
111
  }
110
112
  else {
111
- failures.push(`expected ${expected.code ?? "*"}${expected.message ? ` containing "${expected.message}"` : ""} — not found`);
113
+ failures.push(`expected error ${expected.code ?? "*"}${expected.message ? ` containing "${expected.message}"` : ""} — not found`);
114
+ }
115
+ }
116
+ }
117
+ // Warnings are checked only when the caller declares expect.warnings. Unexpected
118
+ // warnings are not failures (unlike errors) — warnings are advisory and may exist
119
+ // on manifests that are otherwise valid. When expect.warnings is present, every
120
+ // listed warning must be found; extras are ignored.
121
+ if (expectedWarnings.length > 0) {
122
+ for (const expected of expectedWarnings) {
123
+ const match = warnings.find((d) => matchesDiagnostic(d, expected));
124
+ if (match) {
125
+ matched.push(`warning ${expected.code ?? "*"}${expected.message ? ` (${expected.message})` : ""}`);
126
+ }
127
+ else {
128
+ failures.push(`expected warning ${expected.code ?? "*"}${expected.message ? ` containing "${expected.message}"` : ""} — not found`);
112
129
  }
113
130
  }
114
131
  }
115
132
  const passedLines = matched.map((m) => ` ${green("✓")} ${dim(m)}\n`).join("");
116
133
  if (failures.length > 0) {
117
134
  const failedLines = failures.map((f) => ` ${red("✗")} ${f}\n`).join("");
118
- const actualLines = errors.length > 0
119
- ? ` ${dim("actual errors:")}\n` +
120
- errors.map((d) => ` ${dim(`[${d.code}] ${d.message}`)}\n`).join("")
121
- : ` ${dim("no errors produced")}\n`;
135
+ const actualLines = errors.length > 0 || warnings.length > 0
136
+ ? ` ${dim("actual diagnostics:")}\n` +
137
+ [...errors, ...warnings]
138
+ .map((d) => ` ${dim(`[${d.code}] ${d.message}`)}\n`)
139
+ .join("")
140
+ : ` ${dim("no diagnostics produced")}\n`;
122
141
  ctx.stderr.write(bold(red(`Assert.Manifest.${name}: assertion failed`)) + "\n" +
123
142
  passedLines + failedLines + actualLines);
124
143
  ctx.requestExit(1);
@@ -44,14 +44,13 @@ export async function create(manifest, ctx) {
44
44
  return {
45
45
  run: async () => {
46
46
  const { bold, red, green, yellow, dim } = createColors(ctx.stderr);
47
- const declaringModule = manifest.metadata.module ?? "default";
48
47
  const resourcesToCheck = manifest.resources ?? {};
49
48
  const failures = [];
50
49
  const passed = [];
51
50
  const { resources } = ctx.moduleContext;
52
51
  for (const [alias, expected] of Object.entries(resourcesToCheck)) {
53
- if (!ctx.resolveModuleAlias(declaringModule, alias)) {
54
- failures.push(`Import alias '${alias}' not found in module '${declaringModule}'`);
52
+ if (!ctx.moduleContext.hasImport(alias)) {
53
+ failures.push(`Import alias '${alias}' not found in declaring module`);
55
54
  continue;
56
55
  }
57
56
  const snap = resources[alias] ?? {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/assert",
3
- "version": "0.1.12",
3
+ "version": "0.3.0",
4
4
  "description": "Telo Assert module - Assertion resource kinds for Telo manifests.",
5
5
  "keywords": [
6
6
  "telo",
@@ -31,8 +31,8 @@
31
31
  ],
32
32
  "dependencies": {
33
33
  "@sinclair/typebox": "^0.34.48",
34
- "@telorun/analyzer": "0.3.0",
35
- "@telorun/sdk": "0.3.2"
34
+ "@telorun/analyzer": "0.5.0",
35
+ "@telorun/sdk": "0.6.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^20.0.0",
package/src/manifest.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { DEFAULT_MANIFEST_FILENAME, Loader, StaticAnalyzer, type AnalysisDiagnostic, type ManifestAdapter } from "@telorun/analyzer";
1
+ import { DEFAULT_MANIFEST_FILENAME, Loader, StaticAnalyzer, type AnalysisDiagnostic, type ManifestSource } from "@telorun/analyzer";
2
2
  import type { ResourceContext, Runnable } from "@telorun/sdk";
3
3
  import * as fs from "fs/promises";
4
4
  import * as path from "path";
@@ -13,11 +13,12 @@ interface ManifestAssertManifest {
13
13
  source: string;
14
14
  expect: {
15
15
  errors?: ExpectError[];
16
+ warnings?: ExpectError[];
16
17
  loadError?: string;
17
18
  };
18
19
  }
19
20
 
20
- class LocalFileAdapter implements ManifestAdapter {
21
+ class LocalFileSource implements ManifestSource {
21
22
  supports(p: string): boolean {
22
23
  return (
23
24
  p.startsWith("file://") ||
@@ -77,7 +78,7 @@ export async function create(
77
78
  const dim = (t: string) => c("2", t);
78
79
 
79
80
  const name = manifest.metadata.name;
80
- const loader = new Loader([new LocalFileAdapter()]);
81
+ const loader = new Loader([new LocalFileSource()]);
81
82
  const analyzer = new StaticAnalyzer();
82
83
 
83
84
  const resolvedUrl = new URL(manifest.source, ctx.moduleContext.source).toString();
@@ -121,7 +122,9 @@ export async function create(
121
122
 
122
123
  const diagnostics = analyzer.analyze(manifests);
123
124
  const errors = diagnostics.filter((d) => d.severity === 1); // DiagnosticSeverity.Error = 1
125
+ const warnings = diagnostics.filter((d) => d.severity === 2); // DiagnosticSeverity.Warning = 2
124
126
  const expectedErrors = manifest.expect.errors ?? [];
127
+ const expectedWarnings = manifest.expect.warnings ?? [];
125
128
  const failures: string[] = [];
126
129
  const matched: string[] = [];
127
130
 
@@ -143,7 +146,26 @@ export async function create(
143
146
  );
144
147
  } else {
145
148
  failures.push(
146
- `expected ${expected.code ?? "*"}${expected.message ? ` containing "${expected.message}"` : ""} — not found`,
149
+ `expected error ${expected.code ?? "*"}${expected.message ? ` containing "${expected.message}"` : ""} — not found`,
150
+ );
151
+ }
152
+ }
153
+ }
154
+
155
+ // Warnings are checked only when the caller declares expect.warnings. Unexpected
156
+ // warnings are not failures (unlike errors) — warnings are advisory and may exist
157
+ // on manifests that are otherwise valid. When expect.warnings is present, every
158
+ // listed warning must be found; extras are ignored.
159
+ if (expectedWarnings.length > 0) {
160
+ for (const expected of expectedWarnings) {
161
+ const match = warnings.find((d) => matchesDiagnostic(d, expected));
162
+ if (match) {
163
+ matched.push(
164
+ `warning ${expected.code ?? "*"}${expected.message ? ` (${expected.message})` : ""}`,
165
+ );
166
+ } else {
167
+ failures.push(
168
+ `expected warning ${expected.code ?? "*"}${expected.message ? ` containing "${expected.message}"` : ""} — not found`,
147
169
  );
148
170
  }
149
171
  }
@@ -152,10 +174,13 @@ export async function create(
152
174
  const passedLines = matched.map((m) => ` ${green("✓")} ${dim(m)}\n`).join("");
153
175
  if (failures.length > 0) {
154
176
  const failedLines = failures.map((f) => ` ${red("✗")} ${f}\n`).join("");
155
- const actualLines = errors.length > 0
156
- ? ` ${dim("actual errors:")}\n` +
157
- errors.map((d) => ` ${dim(`[${d.code}] ${d.message}`)}\n`).join("")
158
- : ` ${dim("no errors produced")}\n`;
177
+ const actualLines =
178
+ errors.length > 0 || warnings.length > 0
179
+ ? ` ${dim("actual diagnostics:")}\n` +
180
+ [...errors, ...warnings]
181
+ .map((d) => ` ${dim(`[${d.code}] ${d.message}`)}\n`)
182
+ .join("")
183
+ : ` ${dim("no diagnostics produced")}\n`;
159
184
  ctx.stderr.write(
160
185
  bold(red(`Assert.Manifest.${name}: assertion failed`)) + "\n" +
161
186
  passedLines + failedLines + actualLines,
@@ -50,14 +50,13 @@ export async function create(
50
50
  return {
51
51
  run: async () => {
52
52
  const { bold, red, green, yellow, dim } = createColors(ctx.stderr);
53
- const declaringModule = manifest.metadata.module ?? "default";
54
53
  const resourcesToCheck = manifest.resources ?? {};
55
54
  const failures: string[] = [];
56
55
  const passed: string[] = [];
57
56
  const { resources } = ctx.moduleContext;
58
57
  for (const [alias, expected] of Object.entries(resourcesToCheck)) {
59
- if (!(ctx as any).resolveModuleAlias(declaringModule, alias)) {
60
- failures.push(`Import alias '${alias}' not found in module '${declaringModule}'`);
58
+ if (!ctx.moduleContext.hasImport(alias)) {
59
+ failures.push(`Import alias '${alias}' not found in declaring module`);
61
60
  continue;
62
61
  }
63
62