function propertySort(itemsKey, sortPropertiesKey) {
  let activeObserversMap = new WeakMap();
  let sortPropertyDidChangeMap = new WeakMap();

  if (EMBER_METAL_TRACKED_PROPERTIES) {
    let cp = computed(`${itemsKey}.[]`, `${sortPropertiesKey}.[]`, function(key) {
      let sortProperties = get(this, sortPropertiesKey);

      assert(
        `The sort definition for '${key}' on ${this} must be a function or an array of strings`,
        isArray(sortProperties) && sortProperties.every(s => typeof s === 'string')
      );

      let itemsKeyIsAtThis = itemsKey === '@this';
      let normalizedSortProperties = normalizeSortProperties(sortProperties);

      let items = itemsKeyIsAtThis ? this : get(this, itemsKey);
      if (!isArray(items)) {
        return emberA();
      }

      if (normalizedSortProperties.length === 0) {
        return emberA(items.slice());
      } else {
        return sortByNormalizedSortProperties(items, normalizedSortProperties);
      }
    }).readOnly();

    descriptorForDecorator(cp).auto();

    return cp;
  } else {
    return computed(`${sortPropertiesKey}.[]`, function(key) {
      let sortProperties = get(this, sortPropertiesKey);

      assert(
        `The sort definition for '${key}' on ${this} must be a function or an array of strings`,
        isArray(sortProperties) && sortProperties.every(s => typeof s === 'string')
      );

      // Add/remove property observers as required.
      let activeObservers = activeObserversMap.get(this);

      if (!sortPropertyDidChangeMap.has(this)) {
        sortPropertyDidChangeMap.set(this, function() {
          notifyPropertyChange(this, key);
        });
      }

      let sortPropertyDidChange = sortPropertyDidChangeMap.get(this);

      if (activeObservers !== undefined) {
        activeObservers.forEach(path => removeObserver(this, path, sortPropertyDidChange));
      }

      let itemsKeyIsAtThis = itemsKey === '@this';
      let normalizedSortProperties = normalizeSortProperties(sortProperties);
      if (normalizedSortProperties.length === 0) {
        let path = itemsKeyIsAtThis ? `[]` : `${itemsKey}.[]`;
        addObserver(this, path, sortPropertyDidChange);
        activeObservers = [path];
      } else {
        activeObservers = normalizedSortProperties.map(([prop]) => {
          let path = itemsKeyIsAtThis ? `@each.${prop}` : `${itemsKey}.@each.${prop}`;
          addObserver(this, path, sortPropertyDidChange);
          return path;
        });
      }

      activeObserversMap.set(this, activeObservers);

      let items = itemsKeyIsAtThis ? this : get(this, itemsKey);
      if (!isArray(items)) {
        return emberA();
      }

      if (normalizedSortProperties.length === 0) {
        return emberA(items.slice());
      } else {
        return sortByNormalizedSortProperties(items, normalizedSortProperties);
      }
    }).readOnly();
  }
}
function propertySort(itemsKey, sortPropertiesKey) {
  let activeObserversMap = new WeakMap();
  let sortPropertyDidChangeMap = new WeakMap();

  if (EMBER_METAL_TRACKED_PROPERTIES) {
    let cp = computed(`${itemsKey}.[]`, `${sortPropertiesKey}.[]`, function(key) {
      let sortProperties = get(this, sortPropertiesKey);

      assert(
        `The sort definition for '${key}' on ${this} must be a function or an array of strings`,
        isArray(sortProperties) && sortProperties.every(s => typeof s === 'string')
      );

      let itemsKeyIsAtThis = itemsKey === '@this';
      let normalizedSortProperties = normalizeSortProperties(sortProperties);

      let items = itemsKeyIsAtThis ? this : get(this, itemsKey);
      if (!isArray(items)) {
        return emberA();
      }

      if (normalizedSortProperties.length === 0) {
        return emberA(items.slice());
      } else {
        return sortByNormalizedSortProperties(items, normalizedSortProperties);
      }
    }).readOnly();

    descriptorForDecorator(cp).auto();

    return cp;
  } else {
    return computed(`${sortPropertiesKey}.[]`, function(key) {
      let sortProperties = get(this, sortPropertiesKey);

      assert(
        `The sort definition for '${key}' on ${this} must be a function or an array of strings`,
        isArray(sortProperties) && sortProperties.every(s => typeof s === 'string')
      );

      // Add/remove property observers as required.
      let activeObservers = activeObserversMap.get(this);

      if (!sortPropertyDidChangeMap.has(this)) {
        sortPropertyDidChangeMap.set(this, function() {
          notifyPropertyChange(this, key);
        });
      }

      let sortPropertyDidChange = sortPropertyDidChangeMap.get(this);

      if (activeObservers !== undefined) {
        activeObservers.forEach(path => removeObserver(this, path, sortPropertyDidChange));
      }

      let itemsKeyIsAtThis = itemsKey === '@this';
      let normalizedSortProperties = normalizeSortProperties(sortProperties);
      if (normalizedSortProperties.length === 0) {
        let path = itemsKeyIsAtThis ? `[]` : `${itemsKey}.[]`;
        addObserver(this, path, sortPropertyDidChange);
        activeObservers = [path];
      } else {
        activeObservers = normalizedSortProperties.map(([prop]) => {
          let path = itemsKeyIsAtThis ? `@each.${prop}` : `${itemsKey}.@each.${prop}`;
          addObserver(this, path, sortPropertyDidChange);
          return path;
        });
      }

      activeObserversMap.set(this, activeObservers);

      let items = itemsKeyIsAtThis ? this : get(this, itemsKey);
      if (!isArray(items)) {
        return emberA();
      }

      if (normalizedSortProperties.length === 0) {
        return emberA(items.slice());
      } else {
        return sortByNormalizedSortProperties(items, normalizedSortProperties);
      }
    }).readOnly();
  }
}
function propertySort ( itemsKey , sortPropertiesKey ) { let activeObserversMap = new WeakMap ( ) ; let sortPropertyDidChangeMap = new WeakMap ( ) ; if ( EMBER_METAL_TRACKED_PROPERTIES ) { let cp = computed ( ` ${ itemsKey } ` , ` ${ sortPropertiesKey } ` , function ( key ) { let sortProperties = get ( this , sortPropertiesKey ) ; assert ( ` ${ key } ${ this } ` , isArray ( sortProperties ) && sortProperties . every ( s => typeof s === 'string' ) ) ; let itemsKeyIsAtThis = itemsKey === '@this' ; let normalizedSortProperties = normalizeSortProperties ( sortProperties ) ; let items = itemsKeyIsAtThis ? this : get ( this , itemsKey ) ; if ( ! isArray ( items ) ) { return emberA ( ) ; } if ( normalizedSortProperties . length === 0 ) { return emberA ( items . slice ( ) ) ; } else { return sortByNormalizedSortProperties ( items , normalizedSortProperties ) ; } } ) . readOnly ( ) ; descriptorForDecorator ( cp ) . auto ( ) ; return cp ; } else { return computed ( ` ${ sortPropertiesKey } ` , function ( key ) { let sortProperties = get ( this , sortPropertiesKey ) ; assert ( ` ${ key } ${ this } ` , isArray ( sortProperties ) && sortProperties . every ( s => typeof s === 'string' ) ) ; // Add/remove property observers as required. let activeObservers = activeObserversMap . get ( this ) ; if ( ! sortPropertyDidChangeMap . has ( this ) ) { sortPropertyDidChangeMap . set ( this , function ( ) { notifyPropertyChange ( this , key ) ; } ) ; } let sortPropertyDidChange = sortPropertyDidChangeMap . get ( this ) ; if ( activeObservers !== undefined ) { activeObservers . forEach ( path => removeObserver ( this , path , sortPropertyDidChange ) ) ; } let itemsKeyIsAtThis = itemsKey === '@this' ; let normalizedSortProperties = normalizeSortProperties ( sortProperties ) ; if ( normalizedSortProperties . length === 0 ) { let path = itemsKeyIsAtThis ? ` ` : ` ${ itemsKey } ` ; addObserver ( this , path , sortPropertyDidChange ) ; activeObservers = [ path ] ; } else { activeObservers = normalizedSortProperties . map ( ( [ prop ] ) => { let path = itemsKeyIsAtThis ? ` ${ prop } ` : ` ${ itemsKey } ${ prop } ` ; addObserver ( this , path , sortPropertyDidChange ) ; return path ; } ) ; } activeObserversMap . set ( this , activeObservers ) ; let items = itemsKeyIsAtThis ? this : get ( this , itemsKey ) ; if ( ! isArray ( items ) ) { return emberA ( ) ; } if ( normalizedSortProperties . length === 0 ) { return emberA ( items . slice ( ) ) ; } else { return sortByNormalizedSortProperties ( items , normalizedSortProperties ) ; } } ) . readOnly ( ) ; } }
This one needs to dynamically set up and tear down observers on the itemsKey depending on the sortProperties
This one needs to dynamically set up and tear down observers on the itemsKey depending on the sortProperties
Returns a computed property which sorts the items in the given array of items by the given property name.