@object-ui/core 3.3.0 → 3.3.2

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 (101) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +20 -1
  3. package/dist/actions/ActionRunner.d.ts +9 -0
  4. package/dist/actions/ActionRunner.js +41 -4
  5. package/dist/adapters/ValueDataSource.js +3 -1
  6. package/dist/registry/Registry.d.ts +47 -0
  7. package/dist/registry/Registry.js +92 -0
  8. package/dist/utils/filter-converter.js +25 -5
  9. package/package.json +32 -8
  10. package/.turbo/turbo-build.log +0 -4
  11. package/src/__benchmarks__/core.bench.ts +0 -64
  12. package/src/__tests__/protocols/DndProtocol.test.ts +0 -186
  13. package/src/__tests__/protocols/KeyboardProtocol.test.ts +0 -177
  14. package/src/__tests__/protocols/NotificationProtocol.test.ts +0 -142
  15. package/src/__tests__/protocols/ResponsiveProtocol.test.ts +0 -176
  16. package/src/__tests__/protocols/SharingProtocol.test.ts +0 -188
  17. package/src/actions/ActionEngine.ts +0 -268
  18. package/src/actions/ActionRunner.ts +0 -717
  19. package/src/actions/TransactionManager.ts +0 -521
  20. package/src/actions/UndoManager.ts +0 -215
  21. package/src/actions/__tests__/ActionEngine.test.ts +0 -206
  22. package/src/actions/__tests__/ActionRunner.params.test.ts +0 -134
  23. package/src/actions/__tests__/ActionRunner.test.ts +0 -711
  24. package/src/actions/__tests__/TransactionManager.test.ts +0 -447
  25. package/src/actions/__tests__/UndoManager.test.ts +0 -320
  26. package/src/actions/index.ts +0 -12
  27. package/src/adapters/ApiDataSource.ts +0 -376
  28. package/src/adapters/README.md +0 -180
  29. package/src/adapters/ValueDataSource.ts +0 -459
  30. package/src/adapters/__tests__/ApiDataSource.test.ts +0 -418
  31. package/src/adapters/__tests__/ValueDataSource.test.ts +0 -571
  32. package/src/adapters/__tests__/resolveDataSource.test.ts +0 -144
  33. package/src/adapters/index.ts +0 -15
  34. package/src/adapters/resolveDataSource.ts +0 -79
  35. package/src/builder/__tests__/schema-builder.test.ts +0 -235
  36. package/src/builder/schema-builder.ts +0 -584
  37. package/src/data-scope/DataScopeManager.ts +0 -269
  38. package/src/data-scope/ViewDataProvider.ts +0 -282
  39. package/src/data-scope/__tests__/DataScopeManager.test.ts +0 -211
  40. package/src/data-scope/__tests__/ViewDataProvider.test.ts +0 -270
  41. package/src/data-scope/index.ts +0 -24
  42. package/src/errors/__tests__/errors.test.ts +0 -292
  43. package/src/errors/index.ts +0 -269
  44. package/src/evaluator/ExpressionCache.ts +0 -206
  45. package/src/evaluator/ExpressionContext.ts +0 -118
  46. package/src/evaluator/ExpressionEvaluator.ts +0 -315
  47. package/src/evaluator/FormulaFunctions.ts +0 -398
  48. package/src/evaluator/SafeExpressionParser.ts +0 -893
  49. package/src/evaluator/__tests__/ExpressionCache.test.ts +0 -135
  50. package/src/evaluator/__tests__/ExpressionContext.test.ts +0 -110
  51. package/src/evaluator/__tests__/ExpressionEvaluator.test.ts +0 -558
  52. package/src/evaluator/__tests__/FormulaFunctions.test.ts +0 -447
  53. package/src/evaluator/index.ts +0 -13
  54. package/src/index.ts +0 -38
  55. package/src/protocols/DndProtocol.ts +0 -168
  56. package/src/protocols/KeyboardProtocol.ts +0 -181
  57. package/src/protocols/NotificationProtocol.ts +0 -150
  58. package/src/protocols/ResponsiveProtocol.ts +0 -210
  59. package/src/protocols/SharingProtocol.ts +0 -185
  60. package/src/protocols/index.ts +0 -13
  61. package/src/query/__tests__/query-ast.test.ts +0 -211
  62. package/src/query/__tests__/window-functions.test.ts +0 -275
  63. package/src/query/index.ts +0 -7
  64. package/src/query/query-ast.ts +0 -341
  65. package/src/registry/PluginScopeImpl.ts +0 -259
  66. package/src/registry/PluginSystem.ts +0 -206
  67. package/src/registry/Registry.ts +0 -219
  68. package/src/registry/WidgetRegistry.ts +0 -316
  69. package/src/registry/__tests__/PluginSystem.test.ts +0 -309
  70. package/src/registry/__tests__/Registry.test.ts +0 -293
  71. package/src/registry/__tests__/WidgetRegistry.test.ts +0 -321
  72. package/src/registry/__tests__/plugin-scope-integration.test.ts +0 -283
  73. package/src/theme/ThemeEngine.ts +0 -530
  74. package/src/theme/__tests__/ThemeEngine.test.ts +0 -668
  75. package/src/theme/index.ts +0 -24
  76. package/src/types/index.ts +0 -21
  77. package/src/utils/__tests__/debug-collector.test.ts +0 -102
  78. package/src/utils/__tests__/debug.test.ts +0 -134
  79. package/src/utils/__tests__/expand-fields.test.ts +0 -120
  80. package/src/utils/__tests__/extract-records.test.ts +0 -50
  81. package/src/utils/__tests__/filter-converter.test.ts +0 -118
  82. package/src/utils/__tests__/merge-views-into-objects.test.ts +0 -110
  83. package/src/utils/__tests__/normalize-quick-filter.test.ts +0 -123
  84. package/src/utils/debug-collector.ts +0 -100
  85. package/src/utils/debug.ts +0 -148
  86. package/src/utils/expand-fields.ts +0 -76
  87. package/src/utils/extract-records.ts +0 -33
  88. package/src/utils/filter-converter.ts +0 -133
  89. package/src/utils/merge-views-into-objects.ts +0 -36
  90. package/src/utils/normalize-quick-filter.ts +0 -78
  91. package/src/validation/__tests__/object-validation-engine.test.ts +0 -567
  92. package/src/validation/__tests__/schema-validator.test.ts +0 -118
  93. package/src/validation/__tests__/validation-engine.test.ts +0 -102
  94. package/src/validation/index.ts +0 -10
  95. package/src/validation/schema-validator.ts +0 -344
  96. package/src/validation/validation-engine.ts +0 -528
  97. package/src/validation/validators/index.ts +0 -25
  98. package/src/validation/validators/object-validation-engine.ts +0 -722
  99. package/tsconfig.json +0 -15
  100. package/tsconfig.tsbuildinfo +0 -1
  101. package/vitest.config.ts +0 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @object-ui/core
2
2
 
3
+ ## 3.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@3.3.2
8
+
9
+ ## 3.3.1
10
+
11
+ ### Patch Changes
12
+
13
+ - @object-ui/types@3.3.1
14
+
3
15
  ## 3.3.0
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -79,6 +79,25 @@ This allows the core types and logic to be used in:
79
79
 
80
80
  See [full documentation](https://objectui.org/api/core) for detailed API reference.
81
81
 
82
+ <!-- release-metadata:v3.3.0 -->
83
+
84
+ ## Compatibility
85
+
86
+ - **Node.js:** ≥ 18
87
+ - **TypeScript:** ≥ 5.0 (strict mode)
88
+ - **`@objectstack/spec`:** ^3.3.0
89
+ - **`@objectstack/client`:** ^3.3.0
90
+ - **Tailwind CSS:** ≥ 3.4 (for packages with UI)
91
+
92
+ ## Links
93
+
94
+ - 📚 [Documentation](https://www.objectui.org/docs/core)
95
+ - 📦 [npm package](https://www.npmjs.com/package/@object-ui/core)
96
+ - 📝 [Changelog](./CHANGELOG.md)
97
+ - 🐛 [Report an issue](https://github.com/objectstack-ai/objectui/issues)
98
+ - 🤝 [Contributing Guide](https://github.com/objectstack-ai/objectui/blob/main/CONTRIBUTING.md)
99
+ - 🗺️ [Roadmap](https://github.com/objectstack-ai/objectui/blob/main/ROADMAP.md)
100
+
82
101
  ## License
83
102
 
84
- MIT
103
+ MIT — see [LICENSE](./LICENSE).
@@ -178,6 +178,7 @@ export interface ActionParamDef {
178
178
  }
179
179
  export declare class ActionRunner {
180
180
  private handlers;
181
+ private scripts;
181
182
  private evaluator;
182
183
  private context;
183
184
  private confirmHandler;
@@ -209,6 +210,14 @@ export declare class ActionRunner {
209
210
  setParamCollectionHandler(handler: ParamCollectionHandler): void;
210
211
  registerHandler(actionName: string, handler: ActionHandler): void;
211
212
  unregisterHandler(actionName: string): void;
213
+ /**
214
+ * Register a named script handler. When a `script` action's
215
+ * `target`/`execute` matches the registered name, the handler runs
216
+ * instead of the expression evaluator. Lets dashboards/views wire
217
+ * symbolic action names (e.g. 'export_dashboard_pdf') to JS callbacks.
218
+ */
219
+ registerScript(scriptName: string, handler: ActionHandler): void;
220
+ unregisterScript(scriptName: string): void;
212
221
  execute(action: ActionDef): Promise<ActionResult>;
213
222
  /**
214
223
  * Execute multiple actions in sequence or parallel.
@@ -22,6 +22,12 @@ export class ActionRunner {
22
22
  writable: true,
23
23
  value: new Map()
24
24
  });
25
+ Object.defineProperty(this, "scripts", {
26
+ enumerable: true,
27
+ configurable: true,
28
+ writable: true,
29
+ value: new Map()
30
+ });
25
31
  Object.defineProperty(this, "evaluator", {
26
32
  enumerable: true,
27
33
  configurable: true,
@@ -110,6 +116,18 @@ export class ActionRunner {
110
116
  unregisterHandler(actionName) {
111
117
  this.handlers.delete(actionName);
112
118
  }
119
+ /**
120
+ * Register a named script handler. When a `script` action's
121
+ * `target`/`execute` matches the registered name, the handler runs
122
+ * instead of the expression evaluator. Lets dashboards/views wire
123
+ * symbolic action names (e.g. 'export_dashboard_pdf') to JS callbacks.
124
+ */
125
+ registerScript(scriptName, handler) {
126
+ this.scripts.set(scriptName, handler);
127
+ }
128
+ unregisterScript(scriptName) {
129
+ this.scripts.delete(scriptName);
130
+ }
113
131
  async execute(action) {
114
132
  try {
115
133
  // Resolve the action type
@@ -143,14 +161,21 @@ export class ActionRunner {
143
161
  }
144
162
  // Param collection: if the action defines ActionParam[] to collect,
145
163
  // show a dialog to gather user input before executing.
146
- if (action.actionParams && Array.isArray(action.actionParams) && action.actionParams.length > 0) {
164
+ // Spec defines this as `params: ActionParam[]`; ActionRunner historically
165
+ // used `actionParams` to disambiguate from the static-params object that
166
+ // some custom handlers consume. Accept both — when `params` is an array,
167
+ // treat it as the input-collection definition.
168
+ const paramDefs = action.actionParams && Array.isArray(action.actionParams) ? action.actionParams
169
+ : (Array.isArray(action.params) ? action.params : undefined);
170
+ if (paramDefs && paramDefs.length > 0) {
147
171
  if (this.paramCollectionHandler) {
148
- const collected = await this.paramCollectionHandler(action.actionParams);
172
+ const collected = await this.paramCollectionHandler(paramDefs);
149
173
  if (collected === null) {
150
174
  return { success: false, error: 'Action cancelled by user (params)' };
151
175
  }
152
- // Merge collected params into action.params
153
- action.params = { ...(action.params || {}), ...collected };
176
+ // Merge collected params into action.params as a values map for downstream consumers.
177
+ // (Replace the array form with a values object once collected.)
178
+ action.params = { ...(Array.isArray(action.params) ? {} : (action.params || {})), ...collected };
154
179
  }
155
180
  }
156
181
  // Check for a registered custom handler first
@@ -293,6 +318,18 @@ export class ActionRunner {
293
318
  if (!script) {
294
319
  return { success: false, error: 'No script provided for script action' };
295
320
  }
321
+ // Named script registry wins over the expression evaluator. This lets
322
+ // dashboards/views bind a symbolic action name (e.g. 'export_dashboard_pdf')
323
+ // to a JS callback without piping the literal through ExpressionEvaluator.
324
+ const named = this.scripts.get(script);
325
+ if (named) {
326
+ try {
327
+ return await named(action, this.context);
328
+ }
329
+ catch (error) {
330
+ return { success: false, error: `Script execution failed: ${error.message}` };
331
+ }
332
+ }
296
333
  try {
297
334
  const result = this.evaluator.evaluate(`\${${script}}`);
298
335
  return { success: true, data: result };
@@ -53,7 +53,9 @@ function matchesASTFilter(record, filterNode) {
53
53
  case 'in':
54
54
  return Array.isArray(target) && target.includes(value);
55
55
  case 'not in':
56
- case 'notin': // alias used by convertFiltersToAST
56
+ case 'not_in':
57
+ case 'nin': // canonical (per spec)
58
+ case 'notin': // legacy alias
57
59
  return Array.isArray(target) && !target.includes(value);
58
60
  case 'contains': {
59
61
  const lv = typeof value === 'string' ? value.toLowerCase() : '';
@@ -55,8 +55,23 @@ export type ComponentConfig<T = any> = ComponentMeta & {
55
55
  type: string;
56
56
  component: ComponentRenderer<T>;
57
57
  };
58
+ /**
59
+ * Lazy loader function used by `Registry.registerLazy`. The loader is invoked
60
+ * the first time a missing component type is requested through `getAsync`/the
61
+ * SchemaRenderer fallback path, and is expected to perform a dynamic
62
+ * `import()` of a plugin module whose top-level side-effects call
63
+ * `register()` for that type.
64
+ */
65
+ export type LazyComponentLoader = () => Promise<unknown>;
58
66
  export declare class Registry<T = any> {
59
67
  private components;
68
+ private lazyEntries;
69
+ /**
70
+ * Notifies subscribers that the registry has changed (new components
71
+ * registered). Used by SchemaRenderer to re-render after a lazy plugin
72
+ * load completes.
73
+ */
74
+ private listeners;
60
75
  /**
61
76
  * Register a component with optional namespace support.
62
77
  * If namespace is provided in meta, the component will be registered as "namespace:type".
@@ -76,6 +91,38 @@ export declare class Registry<T = any> {
76
91
  * // Accessible as 'button'
77
92
  */
78
93
  register(type: string, component: ComponentRenderer<T>, meta?: ComponentMeta): void;
94
+ /**
95
+ * Register a lazy-loaded component. The `loader` is a function returning a
96
+ * dynamic `import()` whose target module performs `register()` calls for
97
+ * the given `type` as a top-level side effect.
98
+ *
99
+ * The loader will be invoked the first time `loadLazy(type)` is called (or
100
+ * the first time the SchemaRenderer encounters an unknown component that
101
+ * matches a registered lazy type). Subsequent registrations are idempotent.
102
+ *
103
+ * @example
104
+ * ComponentRegistry.registerLazy('object-map', () => import('@object-ui/plugin-map'), { namespace: 'plugin-map' });
105
+ */
106
+ registerLazy(type: string, loader: LazyComponentLoader, meta?: ComponentMeta): void;
107
+ /**
108
+ * Returns true if `type` (or its namespaced form) has a registered lazy
109
+ * loader awaiting first use.
110
+ */
111
+ hasLazy(type: string, namespace?: string): boolean;
112
+ /**
113
+ * Trigger the lazy loader for `type`, if any. Resolves once the loader
114
+ * completes (whether or not the loaded module actually registered the
115
+ * expected type — caller should re-check the registry afterwards).
116
+ * Returns `undefined` if no lazy entry matches.
117
+ */
118
+ loadLazy(type: string, namespace?: string): Promise<unknown> | undefined;
119
+ /**
120
+ * Subscribe to registry changes (component registrations). Returns an
121
+ * unsubscribe function. Used by React renderers to re-render when a
122
+ * lazy-loaded plugin finishes registering its components.
123
+ */
124
+ subscribe(listener: () => void): () => void;
125
+ private notify;
79
126
  /**
80
127
  * Get a component by type. Supports both namespaced and non-namespaced lookups.
81
128
  *
@@ -13,6 +13,23 @@ export class Registry {
13
13
  writable: true,
14
14
  value: new Map()
15
15
  });
16
+ Object.defineProperty(this, "lazyEntries", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: new Map()
21
+ });
22
+ /**
23
+ * Notifies subscribers that the registry has changed (new components
24
+ * registered). Used by SchemaRenderer to re-render after a lazy plugin
25
+ * load completes.
26
+ */
27
+ Object.defineProperty(this, "listeners", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: new Set()
32
+ });
16
33
  }
17
34
  /**
18
35
  * Register a component with optional namespace support.
@@ -65,6 +82,81 @@ export class Registry {
65
82
  ...meta
66
83
  });
67
84
  }
85
+ // A real component is now available — clear any matching lazy stub so we
86
+ // don't keep holding the loader reference, and notify subscribers.
87
+ this.lazyEntries.delete(fullType);
88
+ this.lazyEntries.delete(type);
89
+ this.notify();
90
+ }
91
+ /**
92
+ * Register a lazy-loaded component. The `loader` is a function returning a
93
+ * dynamic `import()` whose target module performs `register()` calls for
94
+ * the given `type` as a top-level side effect.
95
+ *
96
+ * The loader will be invoked the first time `loadLazy(type)` is called (or
97
+ * the first time the SchemaRenderer encounters an unknown component that
98
+ * matches a registered lazy type). Subsequent registrations are idempotent.
99
+ *
100
+ * @example
101
+ * ComponentRegistry.registerLazy('object-map', () => import('@object-ui/plugin-map'), { namespace: 'plugin-map' });
102
+ */
103
+ registerLazy(type, loader, meta) {
104
+ const fullType = meta?.namespace ? `${meta.namespace}:${type}` : type;
105
+ const entry = { loader, meta };
106
+ this.lazyEntries.set(fullType, entry);
107
+ if (meta?.namespace && !meta?.skipFallback) {
108
+ this.lazyEntries.set(type, entry);
109
+ }
110
+ }
111
+ /**
112
+ * Returns true if `type` (or its namespaced form) has a registered lazy
113
+ * loader awaiting first use.
114
+ */
115
+ hasLazy(type, namespace) {
116
+ if (namespace)
117
+ return this.lazyEntries.has(`${namespace}:${type}`);
118
+ return this.lazyEntries.has(type);
119
+ }
120
+ /**
121
+ * Trigger the lazy loader for `type`, if any. Resolves once the loader
122
+ * completes (whether or not the loaded module actually registered the
123
+ * expected type — caller should re-check the registry afterwards).
124
+ * Returns `undefined` if no lazy entry matches.
125
+ */
126
+ loadLazy(type, namespace) {
127
+ const key = namespace ? `${namespace}:${type}` : type;
128
+ const entry = this.lazyEntries.get(key);
129
+ if (!entry)
130
+ return undefined;
131
+ if (!entry.pending) {
132
+ entry.pending = entry.loader().catch((err) => {
133
+ // Allow retries on failure by clearing the cached promise.
134
+ entry.pending = undefined;
135
+ throw err;
136
+ });
137
+ }
138
+ return entry.pending;
139
+ }
140
+ /**
141
+ * Subscribe to registry changes (component registrations). Returns an
142
+ * unsubscribe function. Used by React renderers to re-render when a
143
+ * lazy-loaded plugin finishes registering its components.
144
+ */
145
+ subscribe(listener) {
146
+ this.listeners.add(listener);
147
+ return () => {
148
+ this.listeners.delete(listener);
149
+ };
150
+ }
151
+ notify() {
152
+ for (const listener of this.listeners) {
153
+ try {
154
+ listener();
155
+ }
156
+ catch (err) {
157
+ console.error('[Registry] listener error', err);
158
+ }
159
+ }
68
160
  }
69
161
  /**
70
162
  * Get a component by type. Supports both namespaced and non-namespaced lookups.
@@ -12,6 +12,9 @@
12
12
  * @returns ObjectStack operator or null if not recognized
13
13
  */
14
14
  export function convertOperatorToAST(operator) {
15
+ // Spec reference: framework/packages/spec/src/data/filter.zod.ts
16
+ // Canonical MongoDB-style keys are camelCase ($startsWith, $endsWith, $notContains).
17
+ // Lowercase aliases are accepted for tolerance.
15
18
  const operatorMap = {
16
19
  '$eq': '=',
17
20
  '$ne': '!=',
@@ -20,11 +23,16 @@ export function convertOperatorToAST(operator) {
20
23
  '$lt': '<',
21
24
  '$lte': '<=',
22
25
  '$in': 'in',
23
- '$nin': 'notin',
24
- '$notin': 'notin',
26
+ '$nin': 'nin',
27
+ '$notin': 'nin',
28
+ '$between': 'between',
25
29
  '$contains': 'contains',
30
+ '$notContains': 'notcontains',
31
+ '$notcontains': 'notcontains',
32
+ '$startsWith': 'startswith',
26
33
  '$startswith': 'startswith',
27
- '$between': 'between',
34
+ '$endsWith': 'endswith',
35
+ '$endswith': 'endswith',
28
36
  };
29
37
  return operatorMap[operator] || null;
30
38
  }
@@ -66,10 +74,21 @@ export function convertFiltersToAST(filter) {
66
74
  console.warn(`[ObjectUI] Warning: $regex operator is not fully supported. ` +
67
75
  `Converting to 'contains' which only supports substring matching, not regex patterns. ` +
68
76
  `Field: '${field}', Value: ${JSON.stringify(operatorValue)}. ` +
69
- `Consider using $contains or $startswith instead.`);
77
+ `Consider using $contains or $startsWith instead.`);
70
78
  conditions.push([field, 'contains', operatorValue]);
71
79
  continue;
72
80
  }
81
+ // $null / $exists translate based on their boolean value (per spec semantics).
82
+ // $null: true → IS NULL | $null: false → IS NOT NULL
83
+ // $exists: true → IS NOT NULL | $exists: false → IS NULL
84
+ if (operator === '$null') {
85
+ conditions.push([field, operatorValue ? 'is_null' : 'is_not_null', true]);
86
+ continue;
87
+ }
88
+ if (operator === '$exists') {
89
+ conditions.push([field, operatorValue ? 'is_not_null' : 'is_null', true]);
90
+ continue;
91
+ }
73
92
  const astOperator = convertOperatorToAST(operator);
74
93
  if (astOperator) {
75
94
  conditions.push([field, astOperator, operatorValue]);
@@ -77,7 +96,8 @@ export function convertFiltersToAST(filter) {
77
96
  else {
78
97
  // Unknown operator - throw error to avoid silent failure
79
98
  throw new Error(`[ObjectUI] Unknown filter operator '${operator}' for field '${field}'. ` +
80
- `Supported operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $contains, $startswith, $between. ` +
99
+ `Supported operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $between, ` +
100
+ `$contains, $notContains, $startsWith, $endsWith, $null, $exists. ` +
81
101
  `If you need exact object matching, use the value directly without an operator.`);
82
102
  }
83
103
  }
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@object-ui/core",
3
- "version": "3.3.0",
3
+ "version": "3.3.2",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
7
7
  "description": "Core logic, types, and validation for Object UI. Zero React dependencies.",
8
- "homepage": "https://www.objectui.org",
8
+ "homepage": "https://www.objectui.org/docs/core",
9
9
  "repository": {
10
10
  "type": "git",
11
- "url": "https://github.com/objectstack-ai/objectui.git",
11
+ "url": "git+https://github.com/objectstack-ai/objectui.git",
12
12
  "directory": "packages/core"
13
13
  },
14
14
  "bugs": {
@@ -25,15 +25,39 @@
25
25
  }
26
26
  },
27
27
  "dependencies": {
28
- "@objectstack/spec": "^4.0.3",
28
+ "@objectstack/spec": "^4.0.4",
29
29
  "lodash": "^4.18.1",
30
- "zod": "^4.3.6",
31
- "@object-ui/types": "3.3.0"
30
+ "zod": "^4.4.3",
31
+ "@object-ui/types": "3.3.2"
32
32
  },
33
33
  "devDependencies": {
34
- "typescript": "^6.0.2",
35
- "vitest": "^4.1.4"
34
+ "typescript": "^6.0.3",
35
+ "vitest": "^4.1.5"
36
36
  },
37
+ "keywords": [
38
+ "objectui",
39
+ "sdui",
40
+ "schema-driven-ui",
41
+ "react",
42
+ "tailwind",
43
+ "shadcn",
44
+ "objectstack",
45
+ "core",
46
+ "engine",
47
+ "expression-engine",
48
+ "action-engine",
49
+ "registry"
50
+ ],
51
+ "author": "ObjectStack Team <team@objectstack.ai>",
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "files": [
56
+ "dist",
57
+ "README.md",
58
+ "CHANGELOG.md",
59
+ "LICENSE"
60
+ ],
37
61
  "scripts": {
38
62
  "build": "tsc",
39
63
  "test": "vitest run",
@@ -1,4 +0,0 @@
1
-
2
- > @object-ui/core@3.3.0 build /home/runner/work/objectui/objectui/packages/core
3
- > tsc
4
-
@@ -1,64 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- /**
10
- * Performance benchmark suite for @object-ui/core.
11
- *
12
- * Part of Q1 2026 roadmap §1.4 Test Coverage Improvement.
13
- *
14
- * Run with: npx vitest bench packages/core/src/__benchmarks__/
15
- */
16
-
17
- import { bench, describe } from 'vitest';
18
- import { ExpressionEvaluator } from '@object-ui/core';
19
- import { ComponentRegistry } from '@object-ui/core';
20
- import { contrastRatio, meetsContrastLevel, hexToHSL } from '@object-ui/core';
21
-
22
- describe('ExpressionEvaluator performance', () => {
23
- const evaluator = new ExpressionEvaluator({ data: { name: 'Alice', age: 30, active: true } });
24
-
25
- bench('evaluate simple string', () => {
26
- evaluator.evaluate('Hello ${data.name}');
27
- });
28
-
29
- bench('evaluate 100 expressions', () => {
30
- for (let i = 0; i < 100; i++) {
31
- evaluator.evaluate('Hello ${data.name}');
32
- }
33
- });
34
- });
35
-
36
- describe('ComponentRegistry performance', () => {
37
- bench('get registered component', () => {
38
- ComponentRegistry.get('button');
39
- });
40
-
41
- bench('has check', () => {
42
- ComponentRegistry.has('button');
43
- });
44
- });
45
-
46
- describe('Theme utilities performance', () => {
47
- bench('hexToHSL conversion', () => {
48
- hexToHSL('#336699');
49
- });
50
-
51
- bench('contrastRatio calculation', () => {
52
- contrastRatio('#000000', '#ffffff');
53
- });
54
-
55
- bench('meetsContrastLevel check', () => {
56
- meetsContrastLevel('#000000', '#ffffff', 'AA');
57
- });
58
-
59
- bench('100 contrast checks', () => {
60
- for (let i = 0; i < 100; i++) {
61
- meetsContrastLevel('#336699', '#ffffff', 'AA');
62
- }
63
- });
64
- });