Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/foundation/core/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@ export function convertIntrospectedSchemaToObjects(

if (foreignKey) {
// This is a lookup field
// Note: name must be set explicitly here since we're creating the config programmatically.
// When defined in YAML (ObjectConfig.fields Record), the name is auto-populated from the key.
fieldConfig = {
name: column.name,
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name property is now explicitly set in both lookup and regular field configurations. This is redundant since the comment on line 114 in the original code states 'If defined within an object map, this is often automatically populated from the key.' Consider documenting why explicit name assignment is now required, or if this is needed for protocol compliance.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added clarifying comments explaining that explicit name assignment is required when creating FieldConfig programmatically (as in database introspection). The auto-population behavior applies only to YAML definitions where the Record key becomes the field name. See commit 9f1b180.

type: 'lookup',
reference_to: foreignKey.referencedTable,
label: toTitleCase(column.name),
Expand All @@ -120,7 +123,10 @@ export function convertIntrospectedSchemaToObjects(
// Regular field
const fieldType = mapDatabaseTypeToFieldType(column.type);

// Note: name must be set explicitly here since we're creating the config programmatically.
// When defined in YAML (ObjectConfig.fields Record), the name is auto-populated from the key.
fieldConfig = {
name: column.name,
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name property is now explicitly set in both lookup and regular field configurations. This is redundant since the comment on line 114 in the original code states 'If defined within an object map, this is often automatically populated from the key.' Consider documenting why explicit name assignment is now required, or if this is needed for protocol compliance.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added clarifying comments explaining that explicit name assignment is required when creating FieldConfig programmatically (as in database introspection). The auto-population behavior applies only to YAML definitions where the Record key becomes the field name. See commit 9f1b180.

type: fieldType,
label: toTitleCase(column.name),
required: !column.nullable
Expand All @@ -133,7 +139,7 @@ export function convertIntrospectedSchemaToObjects(

// Add max length for text fields
if (column.maxLength && (fieldType === 'text' || fieldType === 'textarea')) {
fieldConfig.max_length = column.maxLength;
fieldConfig.maxLength = column.maxLength;
}

// Add default value
Expand Down
9 changes: 4 additions & 5 deletions packages/foundation/core/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,10 @@ export class Validator {
}
}

// Pattern validation (supports both pattern and deprecated regex)
const patternValue = validation.pattern ?? validation.regex;
if (patternValue) {
// Pattern validation
if (validation.pattern) {
try {
const pattern = new RegExp(patternValue);
const pattern = new RegExp(validation.pattern);
if (!pattern.test(String(value))) {
results.push({
rule: `${fieldName}_pattern`,
Expand All @@ -208,7 +207,7 @@ export class Validator {
results.push({
rule: `${fieldName}_pattern`,
valid: false,
message: `Invalid regex pattern: ${patternValue}`,
message: `Invalid regex pattern: ${validation.pattern}`,
severity: 'error',
fields: [fieldName],
});
Expand Down
2 changes: 1 addition & 1 deletion packages/foundation/core/test/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ describe('Utility Functions', () => {
const objects = convertIntrospectedSchemaToObjects(schema);
const fields = objects[0].fields!;

expect(fields.short_text.max_length).toBe(100);
expect(fields.short_text.maxLength).toBe(100);
});

it('should add default value when present', () => {
Expand Down
5 changes: 4 additions & 1 deletion packages/foundation/types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
"schemas"
],
"scripts": {
"build": "tsc && npm run generate:schemas",
"build": "tsc",
"generate:schemas": "node scripts/generate-schemas.js",
"test": "jest --passWithNoTests"
},
"dependencies": {
"@objectstack/spec": "^0.1.1"
},
"devDependencies": {
"ts-json-schema-generator": "^2.4.0"
}
Expand Down
24 changes: 24 additions & 0 deletions packages/foundation/types/src/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@
* LICENSE file in the root directory of this source tree.
*/

// Import and re-export types from the Protocol Constitution (@objectstack/spec)
import type { Action } from '@objectstack/spec';
import { FieldConfig } from "./field";
import { HookAPI } from "./hook"; // Reuse the restricted API interface

/**
* Re-export Protocol Types from the Constitution
*/
export type { Action as SpecAction };

/**
* RUNTIME-SPECIFIC TYPES
* The following types extend the Protocol Action definition with runtime execution capabilities
*/

/**
* Defines the scope of the action.
* - `record`: Acts on a specific record instance (e.g. "Approve Order").
Expand All @@ -24,6 +36,8 @@ export type ActionInputDefinition = Record<string, FieldConfig>;

/**
* Context passed to the action handler execution.
*
* RUNTIME TYPE: Used during action execution.
*/
export interface ActionContext<BaseT = any, InputT = any> {
/** The object this action belongs to. */
Expand Down Expand Up @@ -58,11 +72,19 @@ export interface ActionContext<BaseT = any, InputT = any> {
}

/**
* Runtime Action Configuration
*
* The configuration of an Action visible to the Metadata engine (YAML/JSON side).
* Compatible with Protocol Action but adds runtime-specific options.
*/
export interface ActionConfig {
/** Display label */
label?: string;

/** Description */
description?: string;

/** Icon name */
icon?: string;

/**
Expand Down Expand Up @@ -93,6 +115,8 @@ export interface ActionConfig {

/**
* The full implementation definition (Code side).
*
* RUNTIME TYPE: Includes the handler function for execution.
*/
export interface ActionDefinition<BaseT = any, InputT = any, ReturnT = any> extends ActionConfig {
/**
Expand Down
Loading
Loading