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: improve types and lint #8733

Merged
merged 1 commit into from
Jul 26, 2023
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
13 changes: 9 additions & 4 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,19 @@ module.exports = {
rules: {
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unused-vars': ['error', { args: 'none' }],
'@typescript-eslint/prefer-includes': 'error',
'@typescript-eslint/prefer-ts-expect-error': 'error',
'ember-data/prefer-static-type-import': 'error',
'no-unused-vars': 'off',
'prefer-const': 'off',
'prefer-rest-params': 'off',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'error',
'no-loop-func': 'off',
'@typescript-eslint/no-loop-func': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/no-throw-literal': 'error',
// '@typescript-eslint/prefer-readonly-parameter-types': 'error',
},
},
// Typescript files in non-strict mode
Expand Down Expand Up @@ -210,7 +219,6 @@ module.exports = {
'ember-data-types/q/identifier.ts',
'ember-data-types/q/fetch-manager.ts',
'ember-data-types/q/ember-data-json-api.ts',
'ember-data-types/q/ds-model.ts',
'packages/store/src/-private/managers/record-data-store-wrapper.ts',
'packages/store/src/-private/legacy-model-support/schema-definition-service.ts',
'packages/store/src/-private/network/request-cache.ts',
Expand Down Expand Up @@ -268,7 +276,6 @@ module.exports = {
'packages/adapter/src/-private/fastboot-interface.ts',
'packages/adapter/src/-private/build-url-mixin.ts',
'packages/-ember-data/addon/store.ts',
'tests/main/tests/unit/custom-class-support/custom-class-model-test.ts',
'tests/main/tests/integration/request-state-service-test.ts',
'tests/main/tests/integration/record-data/store-wrapper-test.ts',
'tests/main/tests/integration/record-data/record-data-test.ts',
Expand All @@ -279,9 +286,7 @@ module.exports = {
'tests/main/tests/integration/identifiers/record-identifier-for-test.ts',
'tests/main/tests/integration/identifiers/polymorphic-scenarios-test.ts',
'tests/main/tests/integration/identifiers/new-records-test.ts',
'tests/main/tests/integration/identifiers/lid-reflection-test.ts',
'tests/main/tests/integration/identifiers/configuration-test.ts',
'tests/main/tests/integration/identifiers/cache-test.ts',
'tests/main/tests/helpers/accessors.ts',
],
},
Expand Down
79 changes: 12 additions & 67 deletions ember-data-types/q/ds-model.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,12 @@
import type EmberObject from '@ember/object';

import type { Errors } from '@ember-data/model/-private';
import type Store from '@ember-data/store';

import { Cache } from './cache';
import { StableRecordIdentifier } from './identifier';
import type { JsonApiError } from './record-data-json-api';
import type { AttributeSchema, RelationshipSchema, RelationshipsSchema } from './record-data-schemas';

export type ModelFactory = { class: DSModelSchema };
export type FactoryCache = Record<string, ModelFactory>;
// we put this on the store for interop because it's used by modelFor and
// instantiateRecord as well.
export type ModelStore = Store & { _modelFactoryCache: FactoryCache };

// Placeholder until model.js is typed
export interface DSModel extends EmberObject {
constructor: DSModelSchema;
store: Store;
errors: Errors;
toString(): string;
save(): Promise<DSModel>;
eachRelationship<T>(callback: (this: T, key: string, meta: RelationshipSchema) => void, binding?: T): void;
eachAttribute<T>(callback: (this: T, key: string, meta: AttributeSchema) => void, binding?: T): void;
invalidErrorsChanged(errors: JsonApiError[]): void;
rollbackAttributes(): void;
changedAttributes(): Record<string, [unknown, unknown]>;
[key: string]: unknown;
isDeleted: boolean;
deleteRecord(): void;
unloadRecord(): void;
_notifyProperties(keys: string[]): void;
}

// Implemented by both ShimModelClass and DSModel
export interface ModelSchema {
modelName: string;
fields: Map<string, 'attribute' | 'belongsTo' | 'hasMany'>;
attributes: Map<string, AttributeSchema>;
relationshipsByName: Map<string, RelationshipSchema>;
eachAttribute<T>(callback: (this: T, key: string, attribute: AttributeSchema) => void, binding?: T): void;
eachRelationship<T>(callback: (this: T, key: string, relationship: RelationshipSchema) => void, binding?: T): void;
eachTransformedAttribute<T>(callback: (this: T, key: string, type?: string) => void, binding?: T): void;
toString(): string;
}

export type DSModelCreateArgs = {
_createProps: Record<string, unknown>;
// TODO @deprecate consider deprecating accessing record properties during init which the below is necessary for
_secretInit: {
identifier: StableRecordIdentifier;
cache: Cache;
store: Store;
cb: (record: DSModel, cache: Cache, identifier: StableRecordIdentifier, store: Store) => void;
};
};

// This is the static side of DSModel should become DSModel
// once we can type it.
export interface DSModelSchema extends ModelSchema {
isModel: true;
relationshipsObject: RelationshipsSchema;
extend(...mixins: unknown[]): DSModelSchema;
reopenClass(...mixins: unknown[]): void;
create(createArgs: DSModelCreateArgs): DSModel;
}
import type Model from '@ember-data/model';

export type ModelSchema = Pick<
typeof Model,
| 'modelName'
| 'fields'
| 'attributes'
| 'relationshipsByName'
| 'eachAttribute'
| 'eachRelationship'
| 'eachTransformedAttribute'
>;
2 changes: 1 addition & 1 deletion ember-data-types/q/identifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export interface GenerationMethod {
*/

export type UpdateMethod = {
(identifier: StableRecordIdentifier, newData: ResourceData, bucket: 'record'): void;
(identifier: StableRecordIdentifier, newData: unknown, bucket: 'record'): void;
(identifier: StableIdentifier, newData: unknown, bucket: never): void;
};

Expand Down
4 changes: 2 additions & 2 deletions ember-data-types/q/record-instance.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DSModel } from './ds-model';
import type Model from '@ember-data/model';
/**
@module @ember-data/store
*/
Expand All @@ -14,4 +14,4 @@ import type { DSModel } from './ds-model';
The type belows allows for anything extending object.
*/

export type RecordInstance = DSModel | Record<string, unknown>;
export type RecordInstance = Model | unknown;
8 changes: 5 additions & 3 deletions packages/-ember-data/addon/-private/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import { graphFor } from '@ember-data/graph/-private';
import JSONAPICache from '@ember-data/json-api';
import { LegacyNetworkHandler } from '@ember-data/legacy-compat';
import { FetchManager } from '@ember-data/legacy-compat/-private';
import type Model from '@ember-data/model';
import type { ModelStore } from '@ember-data/model/-private/model';
import { buildSchema, instantiateRecord, modelFor, teardownRecord } from '@ember-data/model/hooks';
import RequestManager from '@ember-data/request';
import Fetch from '@ember-data/request/fetch';
import BaseStore, { CacheHandler, recordIdentifierFor } from '@ember-data/store';
import type { Cache } from '@ember-data/types/cache/cache';
import type { CacheCapabilitiesManager } from '@ember-data/types/q/cache-store-wrapper';
import type { DSModel, ModelSchema, ModelStore } from '@ember-data/types/q/ds-model';
import type { ModelSchema } from '@ember-data/types/q/ds-model';
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
import type { RecordInstance } from '@ember-data/types/q/record-instance';

Expand All @@ -35,12 +37,12 @@ export class Store extends BaseStore {
this: ModelStore,
identifier: StableRecordIdentifier,
createRecordArgs: Record<string, unknown>
): DSModel {
): Model {
return instantiateRecord.call(this, identifier, createRecordArgs);
}

teardownRecord(record: RecordInstance): void {
teardownRecord.call(this, record as DSModel);
teardownRecord.call(this, record as Model);
}

modelFor(type: string): ModelSchema {
Expand Down
1 change: 1 addition & 0 deletions packages/active-record/src/-private/builders/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { copyForwardUrlOptions, extractCacheOptions } from './-utils';

export function query(
type: string,
// eslint-disable-next-line @typescript-eslint/no-shadow
query: QueryParamsSource = {},
options: ConstrainedRequestOptions = {}
): QueryRequestOptions {
Expand Down
53 changes: 26 additions & 27 deletions packages/adapter/src/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -940,43 +940,21 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
*/
groupRecordsForFindMany(store: Store, snapshots: Snapshot[]): Snapshot[][] {
let groups = new Map();
let adapter = this;
let maxURLLength = this.maxURLLength;

snapshots.forEach((snapshot) => {
let baseUrl = adapter._stripIDFromURL(store, snapshot);
let baseUrl = this._stripIDFromURL(store, snapshot);
if (!groups.has(baseUrl)) {
groups.set(baseUrl, []);
}

groups.get(baseUrl).push(snapshot);
});

function splitGroupToFitInUrl(group, maxURLLength, paramNameLength) {
let idsSize = 0;
let baseUrl = adapter._stripIDFromURL(store, group[0]);
let splitGroups: Snapshot[][] = [[]];

group.forEach((snapshot) => {
let additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength;
if (baseUrl.length + idsSize + additionalLength >= maxURLLength) {
idsSize = 0;
splitGroups.push([]);
}

idsSize += additionalLength;

let lastGroupIndex = splitGroups.length - 1;
splitGroups[lastGroupIndex].push(snapshot);
});

return splitGroups;
}

let groupsArray: Snapshot[][] = [];
groups.forEach((group, key) => {
let paramNameLength = '&ids%5B%5D='.length;
let splitGroups = splitGroupToFitInUrl(group, maxURLLength, paramNameLength);
let splitGroups = splitGroupToFitInUrl(store, this, group, maxURLLength, paramNameLength);

splitGroups.forEach((splitGroup) => groupsArray.push(splitGroup));
});
Expand Down Expand Up @@ -1408,7 +1386,7 @@ function handleAbort(requestData: RequestData, responseData: ResponseData): Abor
//From http://stackoverflow.com/questions/280634/endswith-in-javascript
function endsWith(string: string, suffix: string): boolean {
if (typeof String.prototype.endsWith !== 'function') {
return string.indexOf(suffix, string.length - suffix.length) !== -1;
return string.includes(suffix, string.length - suffix.length);
} else {
return string.endsWith(suffix);
}
Expand All @@ -1430,7 +1408,7 @@ function fetchErrorHandler(
response: Response,
errorThrown,
requestData: RequestData
) {
): Error {
let responseData = fetchResponseData(response);

if (responseData.status === 200 && payload instanceof Error) {
Expand Down Expand Up @@ -1519,7 +1497,7 @@ export function fetchOptions(
// If no options are passed, Ember Data sets `data` to an empty object, which we test for.
if (Object.keys(options.data).length && options.url) {
// Test if there are already query params in the url (mimics jQuey.ajax).
const queryParamDelimiter = options.url.indexOf('?') > -1 ? '&' : '?';
const queryParamDelimiter = options.url.includes('?') ? '&' : '?';
options.url += `${queryParamDelimiter}${serializeQueryParams(options.data)}`;
}
} else {
Expand Down Expand Up @@ -1567,4 +1545,25 @@ function ajaxOptions(options: JQueryRequestInit, adapter: RESTAdapter): JQueryRe
return options;
}

function splitGroupToFitInUrl(store, adapter, group, maxURLLength, paramNameLength) {
let idsSize = 0;
let baseUrl = adapter._stripIDFromURL(store, group[0]);
let splitGroups: Snapshot[][] = [[]];

group.forEach((snapshot) => {
let additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength;
if (baseUrl.length + idsSize + additionalLength >= maxURLLength) {
idsSize = 0;
splitGroups.push([]);
}

idsSize += additionalLength;

let lastGroupIndex = splitGroups.length - 1;
splitGroups[lastGroupIndex].push(snapshot);
});

return splitGroups;
}

export default RESTAdapter;
40 changes: 20 additions & 20 deletions packages/graph/src/-private/graph/-edge-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,18 +194,18 @@ function assertConfiguration(info: EdgeDefinition, type: string, key: string) {
return true;
}

let isRHS =
let _isRHS =
key === info.rhs_relationshipName &&
(type === info.rhs_baseModelName || // base or non-polymorphic
// if the other side is polymorphic then we need to scan our modelNames
(info.lhs_isPolymorphic && info.rhs_modelNames.indexOf(type) !== -1)); // polymorphic
let isLHS =
(info.lhs_isPolymorphic && info.rhs_modelNames.includes(type))); // polymorphic
let _isLHS =
key === info.lhs_relationshipName &&
(type === info.lhs_baseModelName || // base or non-polymorphic
// if the other side is polymorphic then we need to scan our modelNames
(info.rhs_isPolymorphic && info.lhs_modelNames.indexOf(type) !== -1)); // polymorphic;
(info.rhs_isPolymorphic && info.lhs_modelNames.includes(type))); // polymorphic;

if (!isRHS && !isLHS) {
if (!_isRHS && !_isLHS) {
/*
this occurs when we are likely polymorphic but not configured to be polymorphic
most often due to extending a class that has a relationship definition on it.
Expand Down Expand Up @@ -259,10 +259,10 @@ function assertConfiguration(info: EdgeDefinition, type: string, key: string) {
```

*/
if (key === info.lhs_relationshipName && info.lhs_modelNames.indexOf(type) !== -1) {
if (key === info.lhs_relationshipName && info.lhs_modelNames.includes(type)) {
// parentIdentifier, parentDefinition, addedIdentifier, store
assertInheritedSchema(info.lhs_definition, type);
} else if (key === info.rhs_relationshipName && info.rhs_modelNames.indexOf(type) !== -1) {
} else if (key === info.rhs_relationshipName && info.rhs_modelNames.includes(type)) {
assertInheritedSchema(info.lhs_definition, type);
}
// OPEN AN ISSUE :: we would like to improve our errors but need to understand what corner case got us here
Expand All @@ -271,7 +271,7 @@ function assertConfiguration(info: EdgeDefinition, type: string, key: string) {
);
}

if (isRHS && isLHS) {
if (_isRHS && _isLHS) {
// not sure how we get here but it's probably the result of some form of inheritance
// without having specified polymorphism correctly leading to it not being self-referential
// OPEN AN ISSUE :: we would like to improve our errors but need to understand what corner case got us here
Expand All @@ -295,7 +295,7 @@ export function isLHS(info: EdgeDefinition, type: string, key: string): boolean
isSelfReferential === true || // itself
type === info.lhs_baseModelName || // base or non-polymorphic
// if the other side is polymorphic then we need to scan our modelNames
(info.rhs_isPolymorphic && info.lhs_modelNames.indexOf(type) !== -1) // polymorphic
(info.rhs_isPolymorphic && info.lhs_modelNames.includes(type)) // polymorphic
);
}

Expand All @@ -315,7 +315,7 @@ export function isRHS(info: EdgeDefinition, type: string, key: string): boolean
isSelfReferential === true || // itself
type === info.rhs_baseModelName || // base or non-polymorphic
// if the other side is polymorphic then we need to scan our modelNames
(info.lhs_isPolymorphic && info.rhs_modelNames.indexOf(type) !== -1) // polymorphic
(info.lhs_isPolymorphic && info.rhs_modelNames.includes(type)) // polymorphic
);
}

Expand Down Expand Up @@ -355,11 +355,11 @@ export function upgradeDefinition(
if (polymorphicLookup[type]) {
const altTypes = Object.keys(polymorphicLookup[type] as {});
for (let i = 0; i < altTypes.length; i++) {
let cached = expandingGet<EdgeDefinition | null>(cache, altTypes[i], propertyName);
if (cached) {
expandingSet<EdgeDefinition | null>(cache, type, propertyName, cached);
cached.rhs_modelNames.push(type);
return cached;
const _cached = expandingGet<EdgeDefinition | null>(cache, altTypes[i], propertyName);
if (_cached) {
expandingSet<EdgeDefinition | null>(cache, type, propertyName, _cached);
_cached.rhs_modelNames.push(type);
return _cached;
}
}
}
Expand Down Expand Up @@ -410,13 +410,13 @@ export function upgradeDefinition(
.getSchemaDefinitionService()
.relationshipsDefinitionFor({ type: inverseType });
assert(`Expected to have a relationship definition for ${inverseType} but none was found.`, inverseDefinitions);
let meta = inverseDefinitions[inverseKey];
let metaFromInverse = inverseDefinitions[inverseKey];
assert(
`Expected a relationship schema for '${inverseType}.${inverseKey}' to match the inverse of '${type}.${propertyName}', but no relationship schema was found.`,
meta
metaFromInverse
);

inverseDefinition = upgradeMeta(meta);
inverseDefinition = upgradeMeta(metaFromInverse);
}
}

Expand Down Expand Up @@ -484,8 +484,8 @@ export function upgradeDefinition(
cached.hasInverse !== false
);

let isLHS = cached.lhs_baseModelName === baseType;
let modelNames = isLHS ? cached.lhs_modelNames : cached.rhs_modelNames;
let _isLHS = cached.lhs_baseModelName === baseType;
let modelNames = _isLHS ? cached.lhs_modelNames : cached.rhs_modelNames;
// make this lookup easier in the future by caching the key
modelNames.push(type);
expandingSet<EdgeDefinition | null>(cache, type, propertyName, cached);
Expand Down
Loading
Loading