Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: lint class member order #1239

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
18 changes: 16 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module.exports = {
sourceType: 'module',
project: ['./tsconfig.eslint.json'],
},
plugins: ['@typescript-eslint', 'prettier', 'jest', 'jest-formatting'],
plugins: ['@typescript-eslint', 'prettier', 'jest', 'jest-formatting', 'sort-class-members'],
rules: {
/**********/
/** Style */
Expand Down Expand Up @@ -48,7 +48,21 @@ module.exports = {
alphabetize: { order: 'asc', caseInsensitive: true },
},
],

"sort-class-members/sort-class-members": [
2,
{
"order": [
"[static-properties]",
"[static-methods]",
"[properties]",
"constructor",
"[conventional-private-properties]",
"[methods]",
"[conventional-private-methods]"
],
"accessorPairPositioning": "getThenSet"
}
],
/***********************************/
/* Stricter rules than airbnb-base */
/***********************************/
Expand Down
1 change: 1 addition & 0 deletions packages/_example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"db:seed": "ts-node scripts/db-seed.ts"
},
"devDependencies": {
"eslint-plugin-sort-class-members": "^1.21.0",
"ts-node": "^10.9.2"
}
}
10 changes: 5 additions & 5 deletions packages/agent/src/framework-mounter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ export default class FrameworkMounter {
private readonly prefix: string;
private readonly logger: Logger;

/** Compute the prefix that the main router should be mounted at in the client's application */
private get completeMountPrefix(): string {
return path.posix.join('/', this.prefix, 'forest');
}

constructor(prefix: string, logger: Logger) {
this.prefix = prefix;
this.logger = logger;
}

/** Compute the prefix that the main router should be mounted at in the client's application */
private get completeMountPrefix(): string {
return path.posix.join('/', this.prefix, 'forest');
}

protected async mount(router: Router): Promise<void> {
for (const task of this.onFirstStart) await task(); // eslint-disable-line no-await-in-loop

Expand Down
8 changes: 4 additions & 4 deletions packages/agent/src/routes/access/api-chart-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ import CollectionRoute from '../collection-route';
export default class CollectionApiChartRoute extends CollectionRoute {
private chartName: string;

get chartUrlSlug(): string {
return this.escapeUrlSlug(this.chartName);
}

constructor(
services: ForestAdminHttpDriverServices,
options: AgentOptionsWithDefaults,
Expand All @@ -28,6 +24,10 @@ export default class CollectionApiChartRoute extends CollectionRoute {
this.chartName = chartName;
}

get chartUrlSlug(): string {
return this.escapeUrlSlug(this.chartName);
}

setupRoutes(router: Router): void {
// Mount both GET and POST, respectively for smart and api charts.
const suffix = `/_charts/${this.collectionUrlSlug}/${this.chartUrlSlug}`;
Expand Down
8 changes: 4 additions & 4 deletions packages/agent/src/routes/access/api-chart-datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ export default class DataSourceApiChartRoute extends BaseRoute {
private dataSource: DataSource;
private chartName: string;

get chartUrlSlug(): string {
return this.escapeUrlSlug(this.chartName);
}

constructor(
services: ForestAdminHttpDriverServices,
options: AgentOptionsWithDefaults,
Expand All @@ -31,6 +27,10 @@ export default class DataSourceApiChartRoute extends BaseRoute {
this.chartName = chartName;
}

get chartUrlSlug(): string {
return this.escapeUrlSlug(this.chartName);
}

setupRoutes(router: Router): void {
// Mount both GET and POST, respectively for smart and api charts.
const suffix = `/_charts/${this.chartUrlSlug}`;
Expand Down
3 changes: 1 addition & 2 deletions packages/agent/src/routes/base-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ export default abstract class BaseRoute {
protected readonly services: ForestAdminHttpDriverServices;
protected readonly options: AgentOptionsWithDefaults;

abstract get type(): RouteType;

constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults) {
this.services = services;
this.options = options;
}
abstract get type(): RouteType;

async bootstrap(): Promise<void> {
// Do nothing by default
Expand Down
16 changes: 8 additions & 8 deletions packages/agent/src/routes/collection-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ export default abstract class CollectionRoute extends BaseRoute {
private readonly collectionName: string;
protected readonly dataSource: DataSource;

protected get collection(): Collection {
return this.dataSource.getCollection(this.collectionName);
}

protected get collectionUrlSlug(): string {
return this.escapeUrlSlug(this.collectionName);
}

constructor(
services: ForestAdminHttpDriverServices,
options: AgentOptionsWithDefaults,
Expand All @@ -28,4 +20,12 @@ export default abstract class CollectionRoute extends BaseRoute {
this.collectionName = collectionName;
this.dataSource = dataSource;
}

protected get collection(): Collection {
return this.dataSource.getCollection(this.collectionName);
}

protected get collectionUrlSlug(): string {
return this.escapeUrlSlug(this.collectionName);
}
}
188 changes: 94 additions & 94 deletions packages/agent/src/routes/modification/action/action-authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,100 @@ type CanPerformCustomActionParams = {
};

export default class ActionAuthorizationService {
private static async canPerformConditionalCustomAction(
caller: Caller,
collection: Collection,
requestFilter: Filter,
condition?: unknown,
) {
if (condition) {
const [requestRecordsCount, matchingRecordsCount] = await Promise.all([
ActionAuthorizationService.aggregateCountConditionIntersection(
caller,
collection,
requestFilter,
),
ActionAuthorizationService.aggregateCountConditionIntersection(
caller,
collection,
requestFilter,
condition,
),
]);

// If all records condition the condition everything is ok
// Otherwise when some records don't match the condition then the user
// is not allow to perform the conditional action
return matchingRecordsCount === requestRecordsCount;
}

return true;
}

private static async aggregateCountConditionIntersection(
caller: Caller,
collection: Collection,
requestFilter: Filter,
condition?: unknown,
) {
try {
// Override request filter with condition if any
const conditionalFilter = requestFilter.override({
conditionTree: condition
? ConditionTreeFactory.intersect(
ConditionTreeParser.fromPlainObject(collection, condition),
requestFilter.conditionTree,
)
: requestFilter.conditionTree,
});

const rows = await collection.aggregate(
caller,
conditionalFilter,
new Aggregation({
operation: 'Count',
}),
);

return (rows?.[0]?.value as number) ?? 0;
} catch (error) {
throw new InvalidActionConditionError();
}
}

/**
* Given a map it groups keys based on their hash values
*/
private static transformToRolesIdsGroupByConditions<T>(
actionConditionsByRoleId: Map<number, T>,
): {
roleIds: number[];
condition: T;
}[] {
const rolesIdsGroupByConditions = Array.from(
actionConditionsByRoleId,
([roleId, condition]) => {
return {
roleId,
condition,
conditionHash: hashObject(condition as Record<string, unknown>, { respectType: false }),
};
},
).reduce((acc, current) => {
const { roleId, condition, conditionHash } = current;

if (acc.has(conditionHash)) {
acc.get(conditionHash).roleIds.push(roleId);
} else {
acc.set(conditionHash, { roleIds: [roleId], condition });
}

return acc;
}, new Map<string, { roleIds: number[]; condition: T }>());

return Array.from(rolesIdsGroupByConditions.values());
}

constructor(private readonly forestAdminClient: ForestAdminClient) {}

public async assertCanTriggerCustomAction({
Expand Down Expand Up @@ -274,98 +368,4 @@ export default class ActionAuthorizationService {
roleIdsAllowedToApproveWithoutConditions,
);
}

private static async canPerformConditionalCustomAction(
caller: Caller,
collection: Collection,
requestFilter: Filter,
condition?: unknown,
) {
if (condition) {
const [requestRecordsCount, matchingRecordsCount] = await Promise.all([
ActionAuthorizationService.aggregateCountConditionIntersection(
caller,
collection,
requestFilter,
),
ActionAuthorizationService.aggregateCountConditionIntersection(
caller,
collection,
requestFilter,
condition,
),
]);

// If all records condition the condition everything is ok
// Otherwise when some records don't match the condition then the user
// is not allow to perform the conditional action
return matchingRecordsCount === requestRecordsCount;
}

return true;
}

private static async aggregateCountConditionIntersection(
caller: Caller,
collection: Collection,
requestFilter: Filter,
condition?: unknown,
) {
try {
// Override request filter with condition if any
const conditionalFilter = requestFilter.override({
conditionTree: condition
? ConditionTreeFactory.intersect(
ConditionTreeParser.fromPlainObject(collection, condition),
requestFilter.conditionTree,
)
: requestFilter.conditionTree,
});

const rows = await collection.aggregate(
caller,
conditionalFilter,
new Aggregation({
operation: 'Count',
}),
);

return (rows?.[0]?.value as number) ?? 0;
} catch (error) {
throw new InvalidActionConditionError();
}
}

/**
* Given a map it groups keys based on their hash values
*/
private static transformToRolesIdsGroupByConditions<T>(
actionConditionsByRoleId: Map<number, T>,
): {
roleIds: number[];
condition: T;
}[] {
const rolesIdsGroupByConditions = Array.from(
actionConditionsByRoleId,
([roleId, condition]) => {
return {
roleId,
condition,
conditionHash: hashObject(condition as Record<string, unknown>, { respectType: false }),
};
},
).reduce((acc, current) => {
const { roleId, condition, conditionHash } = current;

if (acc.has(conditionHash)) {
acc.get(conditionHash).roleIds.push(roleId);
} else {
acc.set(conditionHash, { roleIds: [roleId], condition });
}

return acc;
}, new Map<string, { roleIds: number[]; condition: T }>());

return Array.from(rolesIdsGroupByConditions.values());
}
}
22 changes: 11 additions & 11 deletions packages/agent/src/routes/relation-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import { AgentOptionsWithDefaults } from '../types';
export default abstract class RelationRoute extends CollectionRoute {
protected readonly relationName: string;

constructor(
services: ForestAdminHttpDriverServices,
options: AgentOptionsWithDefaults,
dataSource: DataSource,
collectionName: string,
relationName: string,
) {
super(services, options, dataSource, collectionName);
this.relationName = relationName;
}

protected get foreignCollection(): Collection {
const schema = SchemaUtils.getRelation(
this.collection.schema,
Expand All @@ -20,15 +31,4 @@ export default abstract class RelationRoute extends CollectionRoute {
protected get relationUrlSlug(): string {
return this.escapeUrlSlug(this.relationName);
}

constructor(
services: ForestAdminHttpDriverServices,
options: AgentOptionsWithDefaults,
dataSource: DataSource,
collectionName: string,
relationName: string,
) {
super(services, options, dataSource, collectionName);
this.relationName = relationName;
}
}
Loading
Loading