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
5 changes: 5 additions & 0 deletions .changeset/four-drinks-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@itwin/presentation-shared": major
---

Made `EC.RelationshipConstraint.multiplicity` required.
8 changes: 8 additions & 0 deletions .changeset/ninety-mails-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@itwin/presentation-hierarchies-react": patch
"@itwin/presentation-core-interop": patch
"@itwin/presentation-components": patch
"@itwin/presentation-testing": patch
---

Removed unnecessary, always-truthy condition checks.
2 changes: 1 addition & 1 deletion apps/full-stack-tests/src/ECDbUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export class ECDbBuilder {
}

function isBinding(value: ECSqlBinding | PrimitiveValue): value is ECSqlBinding {
return typeof value === "object" && (value as ECSqlBinding).type !== undefined && (value as ECSqlBinding).value !== undefined;
return typeof value === "object" && "type" in value && "value" in value;
}

export async function createECDb<TResult extends {}>(
Expand Down
5 changes: 1 addition & 4 deletions apps/full-stack-tests/src/IModelUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ async function cloneIModel<TResult extends {}>(
IModelJsFs.copySync(sourceIModelPath, targetIModelPath);

const imodel = StandaloneDb.openFile(targetIModelPath, OpenMode.ReadWrite);
if (!imodel) {
throw new Error("Failed to open cloned iModel");
}
try {
const res = await setup(new TestIModelBuilderImpl(imodel));
imodel.saveChanges("Updated cloned iModel");
Expand Down Expand Up @@ -93,7 +90,7 @@ export function createSchemaContext(imodel: IModelConnection | IModelDb | ECDb)
async getSchemaInfo(schemaKey: Readonly<SchemaKey>, matchType: SchemaMatchType, schemaContext: SchemaContext): Promise<SchemaInfo | undefined> {
const schemaJson = imodel.getSchemaProps(schemaKey.name);
const schemaInfo = await Schema.startLoadingFromJson(schemaJson, schemaContext);
if (schemaInfo !== undefined && schemaInfo.schemaKey.matches(schemaKey as SchemaKey, matchType)) {
if (schemaInfo.schemaKey.matches(schemaKey as SchemaKey, matchType)) {
return schemaInfo;
}
return undefined;
Expand Down
2 changes: 1 addition & 1 deletion apps/full-stack-tests/src/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class ErrorBoundary extends Component<{ children: React.ReactNode }, { er
public override render() {
// in case we got an error - render the error message
if (this.state.error) {
return this.state.error?.message ?? "Error";
return this.state.error.message;
}

// otherwise - render provided child component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ describe("PropertyDataProvider", async () => {
const structArrayRecord = properties.records["/selected-item/"].find((r) => r.property.name.endsWith("StructArrayProperty"));
assert(structArrayRecord?.value.valueFormat === PropertyValueFormat.Array);
const structArrayItemRecord = structArrayRecord.value.items[0];
assert(structArrayItemRecord?.value.valueFormat === PropertyValueFormat.Struct);
assert(structArrayItemRecord.value.valueFormat === PropertyValueFormat.Struct);
const structArrayItemMemberRecord = structArrayItemRecord.value.members.StringMember;
const structArrayMemberField = (await provider.getFieldByPropertyDescription(structArrayItemMemberRecord.property)) as PropertiesField;
expect(structArrayMemberField).to.containSubset({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ describe("Unified selection sync with iModel", () => {
});

afterEach(async () => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (imodel) {
selectionStorage.clearStorage({ imodelKey: createIModelKey(imodel) });
await imodel.close();
Expand Down
1 change: 1 addition & 0 deletions apps/load-tests/tests/src/processors/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */

import { VUContext, VUEvents } from "artillery";
import { decompress as brotliDecompress } from "brotli";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
/* eslint-disable @itwin/no-internal */
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */

import { VUContext, VUEvents } from "artillery";
import { StopWatch } from "@itwin/core-bentley";
Expand Down
2 changes: 0 additions & 2 deletions apps/performance-tests/src/hierarchies/Search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,13 @@ describe("search", () => {
return createHierarchyLevelDefinition(imodelAccess, (alias) => `WHERE ${alias}.ECInstanceId = ${physicalElementsSmallestDecimalId}`);
}
if (
props.parentNode &&
HierarchyNode.isInstancesNode(props.parentNode) &&
props.parentNode.key.instanceKeys.some(({ id }) => Id64.getLocalId(id) === physicalElementsSmallestDecimalId)
) {
return createHierarchyLevelDefinition(imodelAccess, (alias) => `WHERE ${alias}.ECInstanceId IN (${parentIdsArr.join(", ")})`);
}

if (
props.parentNode &&
HierarchyNode.isInstancesNode(props.parentNode) &&
props.parentNode.key.instanceKeys.some(({ id }) => parentIdsArr.includes(Id64.getLocalId(id)))
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class MainThreadBlocksDetector {
if (lateAmount > threshold) {
log(() => `${lateAmount} ms, ${lastTime.toISOString()} - ${currentTime.toISOString()}`);
this._samples.insert(lateAmount);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
} else if (ENABLE_PINGS) {
log(() => `[${currentTime.toISOString()}] Ping`);
}
Expand Down
4 changes: 2 additions & 2 deletions apps/test-app/frontend/src/components/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function App() {

return () => {
IModelApp.resetFormatsProvider();
removeFormatterListener?.();
removeFormatterListener();
void IModelApp.quantityFormatter.resetToUseInternalUnitsProvider();
};
}, [state.imodel]);
Expand Down Expand Up @@ -140,7 +140,7 @@ export function App() {
(acc, curr) => {
// note: the hilite list may contain models and subcategories as well - we don't
// care about them at this moment
acc.elements.push(...(curr.elements ?? []));
acc.elements.push(...curr.elements);
return acc;
},
{ elements: [] },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ function FavoriteFieldActionButton(props: { imodel: IModelConnection; field: Fie
}
}, [field, imodel]);
const { value: isFieldFavorite } = useDebouncedAsyncValue(
useCallback(async () => field && Presentation.favoriteProperties.hasAsync(field, props.imodel, FAVORITES_SCOPE), [field, props.imodel]),
useCallback(async () => Presentation.favoriteProperties.hasAsync(field, props.imodel, FAVORITES_SCOPE), [field, props.imodel]),
);
return (
<div className="favorite-action-button" onClick={toggleFavoriteProperty} onKeyDown={toggleFavoriteProperty} role="button" tabIndex={0}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,6 @@ function createRssHierarchyProvider(): HierarchyProvider & { getSearchPaths: (fi

async getSearchPaths(searchText: string): Promise<HierarchySearchPath[]> {
const feed = await getFeed();
Comment thread
grigasp marked this conversation as resolved.
if (!feed) {
return [];
}
const paths = new Array<HierarchyNodeIdentifiersPath>();

if ((feed.title ?? "<no title>").toLocaleLowerCase().includes(searchText.toLocaleLowerCase())) {
Expand All @@ -474,10 +471,6 @@ function createRssHierarchyProvider(): HierarchyProvider & { getSearchPaths: (fi

async *getNodes({ parentNode }: GetHierarchyNodesProps): AsyncIterableIterator<HierarchyNode> {
const feed = await getFeed();
if (!feed) {
return;
}

async function* generateNodes(): AsyncIterableIterator<HierarchyNode & { key: GenericNodeKey }> {
if (!parentNode) {
yield {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ function Tree({
if (!filteringOptions) {
return;
}
filteringOptions?.setInstanceFilter(toGenericFilter(info));
filteringOptions.setInstanceFilter(toGenericFilter(info));
setFilteringOptions(undefined);
}}
onClose={() => {
Expand Down Expand Up @@ -305,8 +305,8 @@ function getHierarchyDefinition(props: Parameters<UseIModelTreeProps["getHierarc
return new ModelsTreeDefinition(props);
}

const customFormatter: IPrimitiveValueFormatter = async (val) => {
return `THIS_IS_FORMATTED_${val ? JSON.stringify(val.value) : ""}_THIS_IS_FORMATTED`;
const customFormatter: IPrimitiveValueFormatter = async ({ value }) => {
return `THIS_IS_FORMATTED_${JSON.stringify(value)}_THIS_IS_FORMATTED`;
};

function fromGenericFilter(descriptor: Descriptor, filter: GenericInstanceFilter): PresentationInstanceFilterInfo {
Expand Down
17 changes: 6 additions & 11 deletions apps/test-app/frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,12 @@ async function initializeApp() {
BentleyCloudRpcManager.initializeClient(rpcParams, rpcInterfaces);
// __PUBLISH_EXTRACT_END__
}
const readyPromises = new Array<Promise<void>>();

const namespacePromise = IModelApp.localization.registerNamespace("Sample");
if (namespacePromise !== undefined) {
readyPromises.push(namespacePromise);
}

readyPromises.push(initializePresentation());
readyPromises.push(UiFramework.initialize());
readyPromises.push(IModelApp.quantityFormatter.setActiveUnitSystem("metric"));
await Promise.all(readyPromises);
await Promise.all([
IModelApp.localization.registerNamespace("Sample"),
initializePresentation(),
UiFramework.initialize(),
IModelApp.quantityFormatter.setActiveUnitSystem("metric"),
]);
}

async function initializePresentation() {
Expand Down
6 changes: 6 additions & 0 deletions eslint.base.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ module.exports = [
],
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unsafe-enum-comparison": "off",
"@typescript-eslint/no-unnecessary-condition": [
"error",
{
allowConstantLoopConditions: "only-allowed-literals",
},
],
"@typescript-eslint/restrict-template-expressions": [
"error",
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,10 @@ export interface INestedPropertiesAppender extends IPropertiesAppender {
/** @internal */
export namespace IPropertiesAppender {
export function isRoot(appender: IPropertiesAppender): appender is IRootPropertiesAppender {
return (appender as IRootPropertiesAppender).item !== undefined;
return "item" in appender;
}
export function isNested(appender: IPropertiesAppender): appender is INestedPropertiesAppender {
return (appender as INestedPropertiesAppender).finish !== undefined;
return "finish" in appender;
}
}
class StructMembersAppender implements INestedPropertiesAppender {
Expand Down Expand Up @@ -246,7 +246,6 @@ export class InternalPropertyRecordsBuilder implements IContentVisitor {

protected get currentPropertiesAppender(): IPropertiesAppender {
const appender = this._appendersStack[this._appendersStack.length - 1];
assert(appender !== undefined);
return appender;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,19 +289,19 @@ export class ContentDataProvider implements IContentDataProvider {
* Invalidates cached content.
*/
protected invalidateCache(props: CacheInvalidationProps): void {
if (props.descriptor && this.getDefaultContentDescriptor) {
if (props.descriptor) {
this.getDefaultContentDescriptor.cache.keys.length = 0;
this.getDefaultContentDescriptor.cache.values.length = 0;
}
if (props.descriptorConfiguration && this.getContentDescriptor) {
if (props.descriptorConfiguration) {
this.getContentDescriptor.cache.keys.length = 0;
this.getContentDescriptor.cache.values.length = 0;
}
if ((props.content || props.size) && this._getContentAndSize) {
if (props.content || props.size) {
this._getContentAndSize.cache.keys.length = 0;
this._getContentAndSize.cache.values.length = 0;
}
if ((props.formatting || props.content || props.size) && this._getFormattedContentAndSize) {
if (props.formatting || props.content || props.size) {
this._getFormattedContentAndSize.cache.keys.length = 0;
this._getFormattedContentAndSize.cache.values.length = 0;
this._isContentFormatted = false;
Expand All @@ -325,6 +325,8 @@ export class ContentDataProvider implements IContentDataProvider {
this._listeners.push(Presentation.presentation.rulesets().onRulesetModified.addListener(this.onRulesetModified));
this._listeners.push(Presentation.presentation.vars(getRulesetId(this._ruleset)).onVariableChanged.addListener(this.onRulesetVariableChanged));
this._listeners.push(IModelApp.quantityFormatter.onActiveFormattingUnitSystemChanged.addListener(this.onUnitSystemChanged));
// note: IModelApp.formatsProvider may not be available in older versions of core
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
IModelApp.formatsProvider && this._listeners.push(IModelApp.formatsProvider.onFormatsChanged.addListener(this.onFormatsChanged));
}

Expand Down Expand Up @@ -452,6 +454,8 @@ export class ContentDataProvider implements IContentDataProvider {
},
};

// note: `getContentIterator` may not be available in older versions of core
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (Presentation.presentation.getContentIterator) {
const result = await Presentation.presentation.getContentIterator(options);
return result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const findField = (descriptor: Descriptor, recordPropertyName: string): F
}
if (field.isNestedContentField()) {
fieldsSource = field;
// note: `isStructPropertiesField` and `isArrayPropertiesField` may not be available in older versions of core
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
} else if (field.isPropertiesField() && (field.isStructPropertiesField?.() || field.isArrayPropertiesField?.())) {
fieldsSource = field;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ function createGenericInstanceFilterUniqueValueRules(filter: PresentationInstanc
if (filter.operator !== "is-equal" && filter.operator !== "is-not-equal") {
return undefined;
}
if (typeof filter.value?.value !== "string" || typeof filter.value?.displayValue !== "string") {
if (typeof filter.value?.value !== "string" || typeof filter.value.displayValue !== "string") {
return undefined;
}
const result = createUniqueValueConditions(filter, filter.value.displayValue, filter.value.value);
Expand Down Expand Up @@ -400,7 +400,7 @@ function parseUniqueValuesRule(rules: GenericInstanceFilterRule[], ctx: GenericF

const uniqueValues: UniqueValue[] = [];
for (const rule of rules) {
assert(rule.value?.displayValue !== undefined && rule.value.rawValue !== undefined);
assert(rule.value?.displayValue !== undefined);
const displayValue = rule.value.displayValue;
const value = rule.value.rawValue as Value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export class PresentationLabelsProvider implements IPresentationLabelsProvider {
.pipe(
bufferCount(DEFAULT_KEYS_BATCH_SIZE),
mergeMap((keysBatch, batchIndex) => {
// note: `getDisplayLabelDefinitionsIterator` may not be available in older versions of core
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (Presentation.presentation.getDisplayLabelDefinitionsIterator) {
return from(Presentation.presentation.getDisplayLabelDefinitionsIterator({ imodel: this.imodel, keys: keysBatch })).pipe(
mergeMap((result) => result.items),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export const QuantityPropertyEditorInput = forwardRef<PropertyEditorAttributes,
const koqName = props.propertyRecord.property.kindOfQuantityName ?? props.propertyRecord.property.quantityType;
assert(koqName !== undefined);

const initialValue = (props.propertyRecord.value as PrimitiveValue)?.value as number;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const initialValue = (props.propertyRecord.value as PrimitiveValue)?.value as number | undefined;
return (
<QuantityPropertyValueInput {...props} ref={ref} koqName={koqName} schemaContext={schemaMetadataContext.schemaContext} initialRawValue={initialValue} />
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export function useNavigationPropertyTargetsRuleset(
const [ruleset, setRuleset] = useState<Ruleset>();

useEffect(() => {
let disposed = false;
let disposed = false as boolean;
void (async () => {
const propertyInfo = await getNavigationPropertyInfo(property);
if (!disposed && propertyInfo) {
Expand Down Expand Up @@ -177,6 +177,8 @@ async function getItems(imodel: IModelConnection, ruleset: Ruleset, filter?: str
paging: { size: VALUE_BATCH_SIZE },
};
const items = await new Promise<Item[]>((resolve, reject) => {
// note: `getContentIterator` may not be available in older versions of core
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
(Presentation.presentation.getContentIterator
? from(Presentation.presentation.getContentIterator(requestProps)).pipe(
mergeMap((result) => (result ? result.items : EMPTY)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ function useFormatterAndParser(koqName: string, schemaContext: SchemaContext) {
void findFormatterAndParser();

const listeners = [IModelApp.quantityFormatter.onActiveFormattingUnitSystemChanged.addListener(findFormatterAndParser)];
// note: `IModelApp.formatsProvider` may not be available in older versions of core
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (IModelApp.formatsProvider) {
listeners.push(IModelApp.formatsProvider.onFormatsChanged.addListener(findFormatterAndParser));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ async function getItems({
keys,
};
const items = await new Promise<DisplayValueGroup[]>((resolve) => {
// note: `getDistinctValuesIterator` may not be available in older versions of core
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
(Presentation.presentation.getDistinctValuesIterator
? from(Presentation.presentation.getDistinctValuesIterator(requestProps)).pipe(
mergeMap((result) => result.items),
Expand Down
Loading