ts-procedures 5.4.0 → 5.5.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.
Files changed (50) hide show
  1. package/README.md +21 -0
  2. package/agent_config/claude-code/skills/guide/SKILL.md +1 -0
  3. package/agent_config/claude-code/skills/guide/anti-patterns.md +37 -4
  4. package/agent_config/claude-code/skills/guide/api-reference.md +86 -0
  5. package/agent_config/claude-code/skills/guide/patterns.md +33 -0
  6. package/agent_config/claude-code/skills/review/checklist.md +2 -0
  7. package/agent_config/claude-code/skills/scaffold/templates/hono-api.md +1 -1
  8. package/agent_config/copilot/copilot-instructions.md +4 -0
  9. package/agent_config/cursor/cursorrules +4 -0
  10. package/build/implementations/http/doc-registry.d.ts +12 -0
  11. package/build/implementations/http/doc-registry.js +114 -0
  12. package/build/implementations/http/doc-registry.js.map +1 -0
  13. package/build/implementations/http/doc-registry.test.d.ts +1 -0
  14. package/build/implementations/http/doc-registry.test.js +321 -0
  15. package/build/implementations/http/doc-registry.test.js.map +1 -0
  16. package/build/implementations/types.d.ts +31 -0
  17. package/package.json +5 -2
  18. package/src/errors.test.ts +0 -163
  19. package/src/errors.ts +0 -107
  20. package/src/exports.ts +0 -7
  21. package/src/implementations/http/README.md +0 -260
  22. package/src/implementations/http/express-rpc/README.md +0 -281
  23. package/src/implementations/http/express-rpc/index.test.ts +0 -957
  24. package/src/implementations/http/express-rpc/index.ts +0 -265
  25. package/src/implementations/http/express-rpc/types.ts +0 -16
  26. package/src/implementations/http/hono-api/index.test.ts +0 -1328
  27. package/src/implementations/http/hono-api/index.ts +0 -461
  28. package/src/implementations/http/hono-api/types.ts +0 -16
  29. package/src/implementations/http/hono-rpc/README.md +0 -358
  30. package/src/implementations/http/hono-rpc/index.test.ts +0 -1075
  31. package/src/implementations/http/hono-rpc/index.ts +0 -237
  32. package/src/implementations/http/hono-rpc/types.ts +0 -16
  33. package/src/implementations/http/hono-stream/README.md +0 -526
  34. package/src/implementations/http/hono-stream/index.test.ts +0 -1676
  35. package/src/implementations/http/hono-stream/index.ts +0 -435
  36. package/src/implementations/http/hono-stream/types.ts +0 -29
  37. package/src/implementations/types.ts +0 -127
  38. package/src/index.test.ts +0 -1194
  39. package/src/index.ts +0 -512
  40. package/src/schema/compute-schema.test.ts +0 -128
  41. package/src/schema/compute-schema.ts +0 -88
  42. package/src/schema/extract-json-schema.test.ts +0 -25
  43. package/src/schema/extract-json-schema.ts +0 -15
  44. package/src/schema/parser.test.ts +0 -182
  45. package/src/schema/parser.ts +0 -215
  46. package/src/schema/resolve-schema-lib.test.ts +0 -19
  47. package/src/schema/resolve-schema-lib.ts +0 -29
  48. package/src/schema/types.ts +0 -20
  49. package/src/stack-utils.test.ts +0 -94
  50. package/src/stack-utils.ts +0 -129
@@ -1,88 +0,0 @@
1
- import { schemaParser, TSchemaValidationError } from './parser.js'
2
- import { ProcedureRegistrationError } from '../errors.js'
3
- import { TJSONSchema } from './types.js'
4
- import { DefinitionInfo } from '../stack-utils.js'
5
-
6
- /**
7
- * This function is used to compute the JSON schema and validation functions
8
- * for a given schema.
9
- *
10
- * @param name The name of the procedure
11
- * @param schema Procedure schema
12
- * @param definitionInfo Optional definition info for error reporting
13
- */
14
- export function computeSchema<TParamsSchemaType, TReturnTypeSchemaType, TYieldTypeSchemaType = unknown>(
15
- name: string,
16
- schema?: {
17
- params?: TParamsSchemaType
18
- returnType?: TReturnTypeSchemaType
19
- yieldType?: TYieldTypeSchemaType
20
- input?: Record<string, unknown>
21
- },
22
- // Used for error stack trace details
23
- definitionInfo?: DefinitionInfo
24
- ): {
25
- jsonSchema: {
26
- params?: TJSONSchema
27
- returnType?: TJSONSchema
28
- yieldType?: TJSONSchema
29
- input?: Record<string, TJSONSchema>
30
- }
31
- validations: {
32
- params?: (params?: any) => { errors?: TSchemaValidationError[] }
33
- yield?: (value?: any) => { errors?: TSchemaValidationError[] }
34
- input?: Record<string, (value?: any) => { errors?: TSchemaValidationError[] }>
35
- }
36
- } {
37
- const jsonSchema: {
38
- params?: TJSONSchema
39
- returnType?: TJSONSchema
40
- yieldType?: TJSONSchema
41
- input?: Record<string, TJSONSchema>
42
- } = {
43
- params: undefined,
44
- returnType: undefined,
45
- yieldType: undefined,
46
- input: undefined,
47
- }
48
-
49
- const validations: {
50
- params?: (params?: any) => { errors?: TSchemaValidationError[] }
51
- yield?: (value?: any) => { errors?: TSchemaValidationError[] }
52
- input?: Record<string, (value?: any) => { errors?: TSchemaValidationError[] }>
53
- } = {}
54
-
55
- // Mutual exclusivity: params and input cannot both be defined
56
- if (schema?.params && schema?.input) {
57
- throw new ProcedureRegistrationError(
58
- name,
59
- `schema.params and schema.input are mutually exclusive for procedure "${name}". Use schema.params for flat input or schema.input for structured multi-channel input.`,
60
- definitionInfo
61
- )
62
- }
63
-
64
- if (schema) {
65
- const {
66
- jsonSchema: { params, returnType, yieldType, input },
67
- validation,
68
- } = schemaParser(schema, (errors) => {
69
- throw new ProcedureRegistrationError(
70
- name,
71
- `Error parsing schema for ${name} - ${Object.entries(errors)
72
- .map(([key, error]) => `${key}: ${error}`)
73
- .join(', ')}`,
74
- definitionInfo
75
- )
76
- })
77
-
78
- jsonSchema.params = params
79
- jsonSchema.returnType = returnType
80
- jsonSchema.yieldType = yieldType
81
- jsonSchema.input = input
82
- validations.params = validation.params
83
- validations.yield = validation.yield
84
- validations.input = validation.input
85
- }
86
-
87
- return { jsonSchema, validations }
88
- }
@@ -1,25 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
- import { Type } from 'typebox'
3
- import { v } from 'suretype'
4
- import { extractJsonSchema } from './extract-json-schema.js'
5
-
6
- describe('extractJsonSchema()', () => {
7
- const typebox = Type.Object({ name: Type.String() })
8
- const suretype = v.object({ name: v.string().required() })
9
-
10
- test('it extracts TypeBox json-schema', async () => {
11
- expect(extractJsonSchema(typebox)).toMatchObject({
12
- type: 'object',
13
- properties: { name: { type: 'string' } },
14
- required: ['name'],
15
- })
16
- })
17
-
18
- test('it extracts Suretype json-schema', async () => {
19
- expect(extractJsonSchema(suretype)).toMatchObject({
20
- type: 'object',
21
- properties: { name: { type: 'string' } },
22
- required: ['name'],
23
- })
24
- })
25
- })
@@ -1,15 +0,0 @@
1
- import { extractSingleJsonSchema } from 'suretype'
2
- import { isSuretypeSchema, isTypeboxSchema } from './resolve-schema-lib.js'
3
- import { TJSONSchema } from './types.js'
4
-
5
- export function extractJsonSchema(libSchema: unknown): TJSONSchema | undefined {
6
- if (isTypeboxSchema(libSchema)) {
7
- return libSchema
8
- }
9
-
10
- if (isSuretypeSchema(libSchema)) {
11
- return extractSingleJsonSchema(libSchema)?.schema
12
- }
13
-
14
- return undefined
15
- }
@@ -1,182 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
- import { extractSingleJsonSchema, v } from 'suretype'
3
- import { schemaParser } from './parser.js'
4
- import { Type } from 'typebox'
5
-
6
- describe('schemaParser', () => {
7
- test('it parses params to json-schema', async () => {
8
- let done: () => void = () => void 0
9
- const promise = new Promise<void>((r) => {
10
- done = r
11
- })
12
-
13
- const params = v.object({
14
- name: v.string(),
15
- age: v.number(),
16
- })
17
-
18
- const result = schemaParser(
19
- {
20
- params: params,
21
- },
22
- (errors) => {
23
- throw new Error(JSON.stringify(errors))
24
- },
25
- )
26
-
27
- expect(result.jsonSchema.params).toEqual(
28
- extractSingleJsonSchema(params)?.schema,
29
- )
30
-
31
- done()
32
-
33
- await promise
34
- await promise
35
- })
36
-
37
- test('it parses params and generates a validator function', async () => {
38
- let done: () => void = () => void 0
39
- const promise = new Promise<void>((r) => {
40
- done = r
41
- })
42
-
43
- const params = v.object({
44
- name: v.string(),
45
- age: v.number().required(),
46
- })
47
-
48
- const result = schemaParser(
49
- {
50
- params: params,
51
- },
52
- (errors) => {
53
- throw new Error(JSON.stringify(errors))
54
- },
55
- )
56
-
57
- expect(
58
- result.validation.params?.({
59
- name: 'John',
60
- age: 30,
61
- })?.errors,
62
- ).toBeUndefined()
63
-
64
- expect(
65
- result.validation.params?.({
66
- name: { name: '' },
67
- age: 'poop',
68
- })?.errors,
69
- ).toBeDefined()
70
-
71
- expect(
72
- result.validation.params?.({
73
- name: { name: '' },
74
- age: 'poop',
75
- })?.errors?.length,
76
- ).toEqual(2)
77
-
78
- done()
79
-
80
- await promise
81
- })
82
-
83
- test('it parses returnType to json-schema', async () => {
84
- let done: () => void = () => void 0
85
- const promise = new Promise<void>((r) => {
86
- done = r
87
- })
88
-
89
- const returnType = v.object({
90
- name: v.string(),
91
- age: v.number(),
92
- })
93
-
94
- const result = schemaParser(
95
- {
96
- returnType: returnType,
97
- },
98
- (errors) => {
99
- throw new Error(JSON.stringify(errors))
100
- },
101
- )
102
-
103
- expect(result.jsonSchema.returnType).toEqual(
104
- extractSingleJsonSchema(returnType)?.schema,
105
- )
106
-
107
- done()
108
-
109
- await promise
110
- })
111
-
112
- test('it throws a meaningful error to the dev', async () => {
113
- schemaParser(
114
- // invalid params schema
115
- { params: { test: Type.String() } },
116
- (errors) => {
117
- expect(errors.params).toMatch(/Error extracting json schema schema.params/)
118
- },
119
- )
120
-
121
- schemaParser(
122
- // invalid returnType schema
123
- { returnType: 'string value' },
124
- (errors) => {
125
- expect(errors.returnType).toMatch(/Error extracting json schema schema.returnType/)
126
- },
127
- )
128
- })
129
-
130
- test('it parses multiple schemas correct', async () => {
131
- const schema = schemaParser(
132
- {
133
- params: Type.Object({ a: Type.String() }),
134
- returnType: Type.Object({ b: Type.Null() }),
135
- },
136
- (error) => {
137
- throw new Error(JSON.stringify(error))
138
- },
139
- )
140
-
141
- const schema2= schemaParser(
142
- {
143
- params: Type.Object({ c: Type.String() }),
144
- returnType: Type.Object({ d: Type.Number() }),
145
- },
146
- (error) => {
147
- throw new Error(JSON.stringify(error))
148
- },
149
- )
150
-
151
- expect(schema.validation.params?.({}).errors?.[0]?.message).toMatch(/must have required property 'a'/)
152
- expect(schema2.validation.params?.({ c: 'test' })
153
- ).toMatchObject({})
154
- expect(schema.validation.params?.({}).errors?.[0]?.message).toMatch(/must have required property 'a'/)
155
- })
156
-
157
- test('validation returns error if validator fails to initialize', async () => {
158
- // Create a schema that will pass extraction but creates a validation function
159
- // that handles the uninitialized case gracefully
160
- let parseErrorCalled = false
161
-
162
- const result = schemaParser(
163
- {
164
- // Using a valid schema to get through extraction, but we'll test the guard
165
- params: Type.Object({ name: Type.String() }),
166
- },
167
- () => {
168
- parseErrorCalled = true
169
- },
170
- )
171
-
172
- // The validator should be initialized for valid schemas
173
- expect(result.validation.params).toBeDefined()
174
-
175
- // Test that the validation function works correctly
176
- const validResult = result.validation.params?.({ name: 'test' })
177
- expect(validResult?.errors).toBeUndefined()
178
-
179
- const invalidResult = result.validation.params?.({})
180
- expect(invalidResult?.errors).toBeDefined()
181
- })
182
- })
@@ -1,215 +0,0 @@
1
- import { default as addFormats } from 'ajv-formats'
2
- import * as AJV from 'ajv'
3
- import { extractJsonSchema } from './extract-json-schema.js'
4
- import { TJSONSchema } from './types.js'
5
-
6
- export type TSchemaParsed = {
7
- jsonSchema: {
8
- params?: TJSONSchema
9
- returnType?: TJSONSchema
10
- yieldType?: TJSONSchema
11
- input?: Record<string, TJSONSchema>
12
- }
13
- validation: {
14
- params?: (params: any) => { errors?: TSchemaValidationError[] }
15
- yield?: (value: any) => { errors?: TSchemaValidationError[] }
16
- input?: Record<string, (value: any) => { errors?: TSchemaValidationError[] }>
17
- }
18
- }
19
-
20
- export type TSchemaValidationError = AJV.ErrorObject
21
-
22
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
23
- // @ts-expect-error
24
- const ajv = addFormats(
25
- new AJV.Ajv({
26
- allErrors: true,
27
- coerceTypes: true,
28
- removeAdditional: true,
29
- })
30
- )
31
-
32
- export function schemaParser(
33
- schema: { params?: unknown; returnType?: unknown; yieldType?: unknown; input?: Record<string, unknown> },
34
- onParseError: (errors: Record<string, string>) => void
35
- ): TSchemaParsed {
36
- const jsonSchema: TSchemaParsed['jsonSchema'] = {}
37
- const validation: TSchemaParsed['validation'] = {}
38
-
39
- if (schema.params) {
40
- try {
41
- const extracted = extractJsonSchema(schema.params as TJSONSchema)
42
-
43
- if (extracted) {
44
- jsonSchema.params = extracted
45
- }
46
- } catch (e: any) {
47
- onParseError({
48
- params: `Error extracting json schema schema.params - ${e.message}`,
49
- })
50
- }
51
-
52
- if (!jsonSchema.params) {
53
- onParseError({
54
- params: `Error extracting json schema schema.params - schema.params might be empty or it is not a valid suretype or typebox type`,
55
- })
56
- } else {
57
- let paramsValidator: AJV.ValidateFunction | undefined
58
-
59
- try {
60
- paramsValidator = ajv.compile(jsonSchema.params as TJSONSchema)
61
- } catch (e: any) {
62
- onParseError({
63
- params: `Error compiling schema.params for validator - ${e.message}`,
64
- })
65
- }
66
-
67
- validation.params = (params: any) => {
68
- if (!paramsValidator) {
69
- return { errors: [{ message: 'Validator not initialized', keyword: 'internal' } as TSchemaValidationError] }
70
- }
71
-
72
- const valid = paramsValidator(params)
73
-
74
- if (!valid) {
75
- const errors = paramsValidator.errors
76
-
77
- return {
78
- errors: errors?.length ? errors : undefined,
79
- }
80
- }
81
-
82
- return {}
83
- }
84
- }
85
- }
86
-
87
- if (schema.returnType) {
88
- try {
89
- const extracted = extractJsonSchema(schema.returnType as TJSONSchema)
90
-
91
- jsonSchema.returnType = extracted
92
- } catch (e: any) {
93
- onParseError({
94
- returnType: `Error extracting json schema schema.returnType - ${e.message}`,
95
- })
96
- }
97
-
98
- if (!jsonSchema.returnType) {
99
- onParseError({
100
- returnType: `Error extracting json schema schema.returnType - schema.returnType might be empty or it is not a valid suretype or typebox type`,
101
- })
102
- }
103
- }
104
-
105
- if (schema.yieldType) {
106
- try {
107
- const extracted = extractJsonSchema(schema.yieldType as TJSONSchema)
108
-
109
- if (extracted) {
110
- jsonSchema.yieldType = extracted
111
- }
112
- } catch (e: any) {
113
- onParseError({
114
- yieldType: `Error extracting json schema schema.yieldType - ${e.message}`,
115
- })
116
- }
117
-
118
- if (!jsonSchema.yieldType) {
119
- onParseError({
120
- yieldType: `Error extracting json schema schema.yieldType - schema.yieldType might be empty or it is not a valid suretype or typebox type`,
121
- })
122
- } else {
123
- let yieldValidator: AJV.ValidateFunction | undefined
124
-
125
- try {
126
- yieldValidator = ajv.compile(jsonSchema.yieldType as TJSONSchema)
127
- } catch (e: any) {
128
- onParseError({
129
- yieldType: `Error compiling schema.yieldType for validator - ${e.message}`,
130
- })
131
- }
132
-
133
- validation.yield = (value: any) => {
134
- if (!yieldValidator) {
135
- return { errors: [{ message: 'Validator not initialized', keyword: 'internal' } as TSchemaValidationError] }
136
- }
137
-
138
- const valid = yieldValidator(value)
139
-
140
- if (!valid) {
141
- const errors = yieldValidator.errors
142
-
143
- return {
144
- errors: errors?.length ? errors : undefined,
145
- }
146
- }
147
-
148
- return {}
149
- }
150
- }
151
- }
152
-
153
- if (schema.input) {
154
- jsonSchema.input = {}
155
- validation.input = {}
156
-
157
- for (const [channelName, channelSchema] of Object.entries(schema.input)) {
158
- if (!channelSchema) continue
159
-
160
- let channelJsonSchema: TJSONSchema | undefined
161
-
162
- try {
163
- const extracted = extractJsonSchema(channelSchema as TJSONSchema)
164
- if (extracted) {
165
- channelJsonSchema = extracted
166
- jsonSchema.input[channelName] = extracted
167
- }
168
- } catch (e: any) {
169
- onParseError({
170
- [`input.${channelName}`]: `Error extracting json schema schema.input.${channelName} - ${e.message}`,
171
- })
172
- }
173
-
174
- if (!channelJsonSchema) {
175
- onParseError({
176
- [`input.${channelName}`]: `Error extracting json schema schema.input.${channelName} - might be empty or not a valid suretype or typebox type`,
177
- })
178
- } else {
179
- let channelValidator: AJV.ValidateFunction | undefined
180
-
181
- try {
182
- channelValidator = ajv.compile(channelJsonSchema as TJSONSchema)
183
- } catch (e: any) {
184
- onParseError({
185
- [`input.${channelName}`]: `Error compiling schema.input.${channelName} for validator - ${e.message}`,
186
- })
187
- }
188
-
189
- validation.input[channelName] = (value: any) => {
190
- if (!channelValidator) {
191
- return {
192
- errors: [
193
- { message: 'Validator not initialized', keyword: 'internal' } as TSchemaValidationError,
194
- ],
195
- }
196
- }
197
-
198
- const valid = channelValidator(value)
199
-
200
- if (!valid) {
201
- const errors = channelValidator.errors
202
-
203
- return {
204
- errors: errors?.length ? errors : undefined,
205
- }
206
- }
207
-
208
- return {}
209
- }
210
- }
211
- }
212
- }
213
-
214
- return { jsonSchema, validation }
215
- }
@@ -1,19 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
- import { isSuretypeSchema, isTypeboxSchema } from './resolve-schema-lib.js'
3
- import { Type } from 'typebox'
4
- import { v } from 'suretype'
5
-
6
- describe('lib schema resolvers', () => {
7
- const typebox = Type.Object({ name: Type.String() })
8
- const suretype = v.object({ name: v.string() })
9
-
10
- test('it recognizes TypeBox schema', async () => {
11
- expect(isTypeboxSchema(typebox)).toBe(true)
12
- expect(isTypeboxSchema(suretype)).toBe(false)
13
- })
14
-
15
- test('it recognizes Suretype schema', async () => {
16
- expect(isSuretypeSchema(suretype)).toBe(true)
17
- expect(isSuretypeSchema(typebox)).toBe(false)
18
- })
19
- })
@@ -1,29 +0,0 @@
1
- import { CoreValidator } from 'suretype'
2
- import { Type } from 'typebox'
3
-
4
- export type IsTypeboxSchema<TSchema> = TSchema extends {
5
- static: unknown
6
- params: unknown
7
- }
8
- ? true
9
- : false
10
-
11
- export function isTypeboxSchema(schema: any): schema is Type.TSchema {
12
- return (
13
- // typebox v1
14
- (typeof schema === 'object' && '~kind' in schema) ||
15
- // @sinclair/typebox v0.3x
16
- (typeof schema === 'object' && Symbol.for('TypeBox.Kind') in schema)
17
- )
18
- }
19
-
20
- export type IsSuretypeSchema<TSchema> = TSchema extends {
21
- required: () => object
22
- nullable?: never
23
- }
24
- ? true
25
- : false
26
-
27
- export function isSuretypeSchema(schema: any): schema is CoreValidator<any> {
28
- return typeof schema === 'object' && 'getJsonSchemaObject' in schema
29
- }
@@ -1,20 +0,0 @@
1
- import { CoreValidator, TypeOf } from 'suretype'
2
- import { Static, TSchema } from 'typebox'
3
-
4
- // Determine if the generic "SchemaLibType" is Suretype's CoreValidator or Typebox's TSchema
5
- export type TSchemaLib<SchemaLibType> =
6
- SchemaLibType extends CoreValidator<any>
7
- ? TypeOf<SchemaLibType>
8
- : SchemaLibType extends TSchema
9
- ? Static<SchemaLibType>
10
- : unknown
11
-
12
- // AsyncGenerator type extraction for streaming procedures
13
- export type TSchemaLibGenerator<TYield, TReturn = void> =
14
- AsyncGenerator<TSchemaLib<TYield>, TSchemaLib<TReturn>, unknown>
15
-
16
- export type TJSONSchema = Record<string, any>
17
-
18
- export type Prettify<TObject> = {
19
- [Key in keyof TObject]: TObject[Key]
20
- } & {}
@@ -1,94 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
- import { captureDefinitionInfo, formatDefinitionInfo, DefinitionInfo } from './stack-utils.js'
3
-
4
- describe('Stack Utils', () => {
5
- describe('captureDefinitionInfo', () => {
6
- test('returns definition info with definedAt', () => {
7
- const info = captureDefinitionInfo()
8
-
9
- // Should capture the call site in this test file
10
- expect(info).toBeDefined()
11
- expect(info.definitionStack).toBeDefined()
12
- expect(typeof info.definitionStack).toBe('string')
13
- })
14
-
15
- test('definedAt contains file, line, column when available', () => {
16
- const info = captureDefinitionInfo()
17
-
18
- // The definedAt should be present since we're calling from user code (test file)
19
- if (info.definedAt) {
20
- expect(info.definedAt.file).toBeDefined()
21
- expect(typeof info.definedAt.file).toBe('string')
22
- expect(info.definedAt.line).toBeDefined()
23
- expect(typeof info.definedAt.line).toBe('number')
24
- expect(info.definedAt.line).toBeGreaterThan(0)
25
- expect(info.definedAt.column).toBeDefined()
26
- expect(typeof info.definedAt.column).toBe('number')
27
- expect(info.definedAt.column).toBeGreaterThan(0)
28
- expect(info.definedAt.raw).toBeDefined()
29
- expect(typeof info.definedAt.raw).toBe('string')
30
- }
31
- })
32
-
33
- test('definitionStack contains Error stack trace', () => {
34
- const info = captureDefinitionInfo()
35
-
36
- expect(info.definitionStack).toContain('Error')
37
- expect(info.definitionStack).toContain('at ')
38
- })
39
- })
40
-
41
- describe('formatDefinitionInfo', () => {
42
- test('returns undefined when definedAt is not present', () => {
43
- const info: DefinitionInfo = {}
44
- const result = formatDefinitionInfo(info, 'TestProcedure')
45
-
46
- expect(result).toBeUndefined()
47
- })
48
-
49
- test('returns formatted string when definedAt is present', () => {
50
- const info: DefinitionInfo = {
51
- definedAt: {
52
- file: '/app/procedures/test.ts',
53
- line: 42,
54
- column: 5,
55
- raw: 'at Object.<anonymous> (/app/procedures/test.ts:42:5)',
56
- },
57
- }
58
- const result = formatDefinitionInfo(info, 'TestProcedure')
59
-
60
- expect(result).toBeDefined()
61
- expect(result).toContain('--- Procedure "TestProcedure" defined at ---')
62
- expect(result).toContain('/app/procedures/test.ts:42:5')
63
- })
64
-
65
- test('includes procedure name in formatted output', () => {
66
- const info: DefinitionInfo = {
67
- definedAt: {
68
- file: '/path/to/file.ts',
69
- line: 10,
70
- column: 3,
71
- raw: 'at /path/to/file.ts:10:3',
72
- },
73
- }
74
- const result = formatDefinitionInfo(info, 'MyCustomProcedure')
75
-
76
- expect(result).toContain('"MyCustomProcedure"')
77
- })
78
- })
79
-
80
- describe('integration with procedure creation', () => {
81
- test('captures location from calling code', () => {
82
- // Helper to simulate what happens in Create()
83
- function simulateCreate() {
84
- return captureDefinitionInfo()
85
- }
86
-
87
- const info = simulateCreate()
88
-
89
- // Should have captured the location of the simulateCreate() call
90
- expect(info).toBeDefined()
91
- expect(info.definitionStack).toBeDefined()
92
- })
93
- })
94
- })