Skip to content

Commit d69ff7b

Browse files
authored
Merge pull request #364 from objectstack-ai/copilot/fix-build-and-test
2 parents 7718669 + 9ea6906 commit d69ff7b

8 files changed

Lines changed: 312 additions & 13 deletions

File tree

packages/foundation/core/test/__mocks__/@objectstack/core.ts

Lines changed: 250 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,255 @@ export const createLogger = jest.fn(() => ({
2222
fatal: jest.fn(),
2323
}));
2424

25-
export const ObjectKernel = jest.fn();
25+
class MockMetadataRegistry {
26+
private store = new Map<string, Map<string, any>>();
27+
28+
register(type: string, nameOrConfig: string | any, config?: any): void {
29+
if (!this.store.has(type)) {
30+
this.store.set(type, new Map());
31+
}
32+
const typeMap = this.store.get(type)!;
33+
let name: string;
34+
let item: any;
35+
if (config) {
36+
name = nameOrConfig as string;
37+
item = config;
38+
} else {
39+
item = nameOrConfig;
40+
name = item.id || item.name;
41+
}
42+
typeMap.set(name, item);
43+
}
44+
45+
get<T = any>(type: string, id: string): T | undefined {
46+
const typeMap = this.store.get(type);
47+
const item = typeMap?.get(id);
48+
return item?.content as T;
49+
}
50+
51+
list<T = any>(type: string): T[] {
52+
const typeMap = this.store.get(type);
53+
if (!typeMap) return [];
54+
return Array.from(typeMap.values()).map(item => item.content as T);
55+
}
56+
57+
unregister(type: string, id: string): boolean {
58+
const typeMap = this.store.get(type);
59+
if (!typeMap) return false;
60+
return typeMap.delete(id);
61+
}
62+
63+
getTypes(): string[] {
64+
return Array.from(this.store.keys());
65+
}
66+
67+
getEntry(type: string, id: string): any | undefined {
68+
const typeMap = this.store.get(type);
69+
return typeMap ? typeMap.get(id) : undefined;
70+
}
71+
72+
unregisterPackage(packageName: string): void {
73+
for (const [_type, typeMap] of this.store.entries()) {
74+
const toDelete: string[] = [];
75+
for (const [id, item] of typeMap.entries()) {
76+
if (item.packageName === packageName || item.package === packageName) {
77+
toDelete.push(id);
78+
}
79+
}
80+
toDelete.forEach(id => typeMap.delete(id));
81+
}
82+
}
83+
}
84+
85+
class MockHookManager {
86+
removePackage(_packageName: string): void {
87+
// Mock implementation
88+
}
89+
clear(): void {
90+
// Mock implementation
91+
}
92+
}
93+
94+
class MockActionManager {
95+
removePackage(_packageName: string): void {
96+
// Mock implementation
97+
}
98+
clear(): void {
99+
// Mock implementation
100+
}
101+
}
102+
103+
export class ObjectKernel {
104+
public ql: unknown = null;
105+
public metadata: MockMetadataRegistry;
106+
public hooks: MockHookManager;
107+
public actions: MockActionManager;
108+
private plugins: any[] = [];
109+
private driver: any = null;
110+
111+
constructor(plugins: any[] = []) {
112+
this.plugins = plugins;
113+
this.metadata = new MockMetadataRegistry();
114+
this.hooks = new MockHookManager();
115+
this.actions = new MockActionManager();
116+
}
117+
118+
setDriver(driver: any): void {
119+
this.driver = driver;
120+
}
121+
122+
async start(): Promise<void> {
123+
for (const plugin of this.plugins) {
124+
if (plugin.install) {
125+
await plugin.install({ engine: this });
126+
}
127+
}
128+
for (const plugin of this.plugins) {
129+
if (plugin.onStart) {
130+
await plugin.onStart({ engine: this });
131+
}
132+
}
133+
}
134+
135+
async stop(): Promise<void> {
136+
for (const plugin of this.plugins) {
137+
if (plugin.onStop) {
138+
await plugin.onStop({ engine: this });
139+
}
140+
}
141+
}
142+
143+
getDriver(): any {
144+
const driver = this.plugins.find(p =>
145+
p.constructor.name?.includes('Driver') ||
146+
(typeof p.find === 'function' && typeof p.create === 'function')
147+
);
148+
return driver || this.driver;
149+
}
150+
151+
async seed(): Promise<void> {
152+
// Mock implementation
153+
}
154+
155+
async find(objectName: string, query: any): Promise<{ value: Record<string, any>[]; count: number }> {
156+
const driver = this.getDriver();
157+
if (driver) {
158+
const normalizedQuery: any = {};
159+
if (query.filters) {
160+
normalizedQuery.where = query.filters;
161+
} else if (query.filter) {
162+
normalizedQuery.where = query.filter;
163+
} else if (query.where) {
164+
normalizedQuery.where = query.where;
165+
}
166+
if (query.fields) {
167+
normalizedQuery.fields = query.fields;
168+
}
169+
if (query.sort) {
170+
if (Array.isArray(query.sort) && query.sort.length > 0) {
171+
const firstItem = query.sort[0];
172+
if (firstItem !== undefined) {
173+
if (Array.isArray(firstItem)) {
174+
normalizedQuery.orderBy = query.sort.map((s: any) => ({
175+
field: s[0],
176+
order: s[1]
177+
}));
178+
} else if (typeof firstItem === 'object') {
179+
normalizedQuery.orderBy = query.sort.flatMap((s: any) =>
180+
Object.entries(s).map(([field, order]) => ({
181+
field,
182+
order: (order === -1 || order === 'desc' || order === 'DESC') ? 'desc' : 'asc'
183+
}))
184+
);
185+
}
186+
}
187+
} else if (query.sort) {
188+
normalizedQuery.orderBy = query.sort;
189+
}
190+
} else if (query.orderBy) {
191+
normalizedQuery.orderBy = query.orderBy;
192+
}
193+
if (query.limit !== undefined) {
194+
normalizedQuery.limit = query.limit;
195+
} else if (query.top !== undefined) {
196+
normalizedQuery.limit = query.top;
197+
}
198+
if (query.offset !== undefined) {
199+
normalizedQuery.offset = query.offset;
200+
} else if (query.skip !== undefined) {
201+
normalizedQuery.offset = query.skip;
202+
}
203+
if (query.aggregations) {
204+
normalizedQuery.aggregate = query.aggregations.map((agg: any) => ({
205+
func: agg.function,
206+
field: agg.field,
207+
alias: agg.alias
208+
}));
209+
}
210+
if (query.groupBy) {
211+
normalizedQuery.groupBy = query.groupBy;
212+
}
213+
const results = await driver.find(objectName, normalizedQuery, {});
214+
return { value: results, count: results.length };
215+
}
216+
return { value: [], count: 0 };
217+
}
218+
219+
async get(objectName: string, id: string): Promise<Record<string, any>> {
220+
const driver = this.getDriver();
221+
if (driver) {
222+
return await driver.findOne(objectName, id, {}, {});
223+
}
224+
return {};
225+
}
226+
227+
async create(objectName: string, data: any): Promise<Record<string, any>> {
228+
const driver = this.getDriver();
229+
if (driver) {
230+
return await driver.create(objectName, data, {});
231+
}
232+
return data;
233+
}
234+
235+
async update(objectName: string, id: string, data: any): Promise<Record<string, any>> {
236+
const driver = this.getDriver();
237+
if (driver) {
238+
return await driver.update(objectName, id, data, {});
239+
}
240+
return data;
241+
}
242+
243+
async delete(objectName: string, id: string): Promise<boolean> {
244+
const driver = this.getDriver();
245+
if (driver) {
246+
const result = await driver.delete(objectName, id, {});
247+
return result > 0;
248+
}
249+
return true;
250+
}
251+
252+
getMetadata(_objectName: string): any {
253+
return {};
254+
}
255+
256+
getView(_objectName: string, _viewType?: 'list' | 'form'): any {
257+
return null;
258+
}
259+
}
260+
261+
export class ObjectStackProtocolImplementation {}
262+
263+
export interface PluginContext {
264+
engine: ObjectKernel;
265+
}
266+
267+
export interface ObjectQLPlugin {
268+
name: string;
269+
install?: (ctx: PluginContext) => void | Promise<void>;
270+
onStart?: (ctx: PluginContext) => void | Promise<void>;
271+
}
272+
273+
export { MockMetadataRegistry as MetadataRegistry };
274+
26275
export const LiteKernel = jest.fn();
27276
export const createApiRegistryPlugin = jest.fn();

packages/foundation/core/test/__mocks__/@objectstack/runtime.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,21 @@
1111
class MockMetadataRegistry {
1212
private store = new Map<string, Map<string, any>>();
1313

14-
register(type: string, item: any): void {
14+
register(type: string, nameOrConfig: string | any, config?: any): void {
1515
if (!this.store.has(type)) {
1616
this.store.set(type, new Map());
1717
}
1818
const typeMap = this.store.get(type)!;
19-
typeMap.set(item.id || item.name, item);
19+
let name: string;
20+
let item: any;
21+
if (config) {
22+
name = nameOrConfig as string;
23+
item = config;
24+
} else {
25+
item = nameOrConfig;
26+
name = item.id || item.name;
27+
}
28+
typeMap.set(name, item);
2029
}
2130

2231
get<T = any>(type: string, id: string): T | undefined {

packages/foundation/platform-node/test/__mocks__/@objectstack/runtime.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,21 @@
1111
class MockMetadataRegistry {
1212
private store = new Map<string, Map<string, any>>();
1313

14-
register(type: string, item: any): void {
14+
register(type: string, nameOrConfig: string | any, config?: any): void {
1515
if (!this.store.has(type)) {
1616
this.store.set(type, new Map());
1717
}
1818
const typeMap = this.store.get(type)!;
19-
typeMap.set(item.id || item.name, item);
19+
let name: string;
20+
let item: any;
21+
if (config) {
22+
name = nameOrConfig as string;
23+
item = config;
24+
} else {
25+
item = nameOrConfig;
26+
name = item.id || item.name;
27+
}
28+
typeMap.set(name, item);
2029
}
2130

2231
get<T = any>(type: string, id: string): T | undefined {

packages/foundation/plugin-security/src/storage-database.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export class DatabasePermissionStorage implements IPermissionStorage {
163163
try {
164164
const rows = await driver.find(this.tableName, {});
165165
// Create a shallow copy to avoid issues when deleting during iteration
166-
const items = Array.isArray(rows) ? rows as unknown as PermissionRow[] : [];
166+
const items = Array.isArray(rows) ? [...rows] as unknown as PermissionRow[] : [];
167167
for (const row of items) {
168168
const id = row._id ?? row.id ?? row.object_name;
169169
if (id !== undefined) {

packages/protocols/graphql/test/__mocks__/@objectstack/core.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,21 @@
1111
class MockMetadataRegistry {
1212
private store = new Map<string, Map<string, any>>();
1313

14-
register(type: string, item: any): void {
14+
register(type: string, nameOrConfig: string | any, config?: any): void {
1515
if (!this.store.has(type)) {
1616
this.store.set(type, new Map());
1717
}
1818
const typeMap = this.store.get(type)!;
19-
typeMap.set(item.id || item.name, item);
19+
let name: string;
20+
let item: any;
21+
if (config) {
22+
name = nameOrConfig as string;
23+
item = config;
24+
} else {
25+
item = nameOrConfig;
26+
name = item.id || item.name;
27+
}
28+
typeMap.set(name, item);
2029
}
2130

2231
get<T = any>(type: string, id: string): T | undefined {

packages/protocols/json-rpc/test/__mocks__/@objectstack/core.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,21 @@
1111
class MockMetadataRegistry {
1212
private store = new Map<string, Map<string, any>>();
1313

14-
register(type: string, item: any): void {
14+
register(type: string, nameOrConfig: string | any, config?: any): void {
1515
if (!this.store.has(type)) {
1616
this.store.set(type, new Map());
1717
}
1818
const typeMap = this.store.get(type)!;
19-
typeMap.set(item.id || item.name, item);
19+
let name: string;
20+
let item: any;
21+
if (config) {
22+
name = nameOrConfig as string;
23+
item = config;
24+
} else {
25+
item = nameOrConfig;
26+
name = item.id || item.name;
27+
}
28+
typeMap.set(name, item);
2029
}
2130

2231
get<T = any>(type: string, id: string): T | undefined {

packages/protocols/odata-v4/test/__mocks__/@objectstack/core.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,21 @@
1111
class MockMetadataRegistry {
1212
private store = new Map<string, Map<string, any>>();
1313

14-
register(type: string, item: any): void {
14+
register(type: string, nameOrConfig: string | any, config?: any): void {
1515
if (!this.store.has(type)) {
1616
this.store.set(type, new Map());
1717
}
1818
const typeMap = this.store.get(type)!;
19-
typeMap.set(item.id || item.name, item);
19+
let name: string;
20+
let item: any;
21+
if (config) {
22+
name = nameOrConfig as string;
23+
item = config;
24+
} else {
25+
item = nameOrConfig;
26+
name = item.id || item.name;
27+
}
28+
typeMap.set(name, item);
2029
}
2130

2231
get<T = any>(type: string, id: string): T | undefined {

packages/tools/cli/src/commands/doctor.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,12 @@ export async function doctorCommand(options: DoctorOptions = {}) {
118118
if (fs.existsSync(tsconfigPath)) {
119119
console.log(chalk.gray('\nTypeScript Configuration:'));
120120
try {
121-
const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
121+
const tsconfigRaw = fs.readFileSync(tsconfigPath, 'utf-8');
122+
// Strip single-line and multi-line comments (tsconfig uses JSONC)
123+
const tsconfigClean = tsconfigRaw
124+
.replace(/\/\/.*$/gm, '')
125+
.replace(/\/\*[\s\S]*?\*\//g, '');
126+
const tsconfig = JSON.parse(tsconfigClean);
122127

123128
// Check for recommended settings
124129
const compilerOptions = tsconfig.compilerOptions || {};

0 commit comments

Comments
 (0)