lodash#camelCase TypeScript Examples

The following examples show how to use lodash#camelCase. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From prism-frontend with MIT License 7 votes vote down vote up
function formatLayersCategories(layersList: {
  [key: string]: Array<LayerKey | TableKey>;
}): LayersCategoriesType {
  return map(layersList, (layerKeys, layersListKey) => {
    return {
      title: startCase(layersListKey),
      layers: layerKeys.filter(isLayerKey).map(key => {
        if (typeof key === 'object') {
          const group = (mapKeys(key, (_v, k: string) =>
            camelCase(k),
          ) as unknown) as MenuGroup;
          const mainLayer = group.layers.find(l => l.main);
          const layer = LayerDefinitions[mainLayer?.id as LayerKey];
          // eslint-disable-next-line fp/no-mutation
          layer.group = group;
          return layer;
        }
        return LayerDefinitions[key as LayerKey];
      }),
      tables: layerKeys.filter(isTableKey).map(key => TableDefinitions[key]),
    };
  });
}
Example #2
Source File: utils.ts    From prism-frontend with MIT License 7 votes vote down vote up
function parseStatsApiConfig(maybeConfig: {
  [key: string]: any;
}): StatsApi | undefined {
  const config = mapKeys(maybeConfig, (v, k) => camelCase(k));
  if (checkRequiredKeys(StatsApi, config, true)) {
    return config as StatsApi;
  }
  return undefined;
}
Example #3
Source File: utils.ts    From prism-frontend with MIT License 7 votes vote down vote up
function getTableByKey(key: TableKey): TableType {
  // Typescript does not handle our configuration methods very well
  // So we temporarily override the type of rawTables to make it more flexible.
  const tables = rawTables as Record<string, any>;
  const rawDefinition = {
    id: key,
    ...mapKeys(isTableKey(key) ? tables[key] : {}, (v, k) => camelCase(k)),
  };

  if (isValidTableDefinition(rawDefinition)) {
    return rawDefinition;
  }
  throw new Error(
    `Found invalid table definition for table '${key}'. Check config/tables.json`,
  );
}
Example #4
Source File: helpers.ts    From one-platform with MIT License 6 votes vote down vote up
fetchProjectLHR(serverBaseUrl: string, projectID: string, buildID: string) {
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');
    return fetch(
      `${serverBaseUrl}/v1/projects/${projectID}/builds/${buildID}/runs`,
      {
        method: 'GET',
        headers,
        redirect: 'follow',
      },
    )
      .then(handleFetchError)
      .then((res: any) => {
        if (!res.ok) {
          throw res;
        }
        return res;
      })
      .then((res: any) => res.json())
      .then((results: any) => {
        const scores: LighthouseScoreType[] = [];
        results.forEach((value: any) => {
          const lhr = JSON.parse(value.lhr);
          const data: any = {};
          Object.keys(lhr.categories).forEach((category: any) => {
            data[camelCase(category)] = lhr.categories[category].score;
          });
          scores.push(data);
        });
        return scores;
      })
      .catch((error: any) => {
        throw new Error(error);
      });
  }
Example #5
Source File: fetcher.ts    From po8klasie with GNU General Public License v3.0 6 votes vote down vote up
camelCaseKeys = (o: Record<string, unknown>): Record<string, unknown> | unknown[] => {
  if (isPlainObject(o)) {
    const n: Record<string, unknown> = {};

    Object.keys(o).forEach((k) => {
      n[camelCase(k)] = camelCaseKeys(o[k] as Record<string, unknown>);
    });

    return n;
  }
  if (Array.isArray(o)) {
    return o.map((i) => camelCaseKeys(i));
  }

  return o;
}
Example #6
Source File: HtmlStringToReactNodes.tsx    From easy-email with MIT License 6 votes vote down vote up
function getStyle(styleText: string | null) {
  if (!styleText) return undefined;
  return styleText.split(';').reduceRight((a: any, b: any) => {
    const arr = b.split(/\:(?!\/)/);
    if (arr.length < 2) return a;
    a[camelCase(arr[0])] = arr[1];
    return a;
  }, {});
}
Example #7
Source File: HtmlStringToPreviewReactNodes.tsx    From easy-email with MIT License 6 votes vote down vote up
function getStyle(styleText: string | null) {
  if (!styleText) return undefined;
  return styleText.split(';').reduceRight((a: any, b: any) => {
    const arr = b.split(/\:(?!\/)/);
    if (arr.length < 2) return a;
    a[camelCase(arr[0])] = arr[1];
    return a;
  }, {});
}
Example #8
Source File: generateBlockJSX.ts    From easy-email with MIT License 6 votes vote down vote up
BlockManager.getBlocks().forEach((item) => {
  const fileName = capitalizeFirstLetter(camelCase(item.type));
  const interfaceName = `I${fileName}`;
  const code = `
  import { omit } from 'lodash';
  import { BasicType } from '@core/constants';
  import { RecursivePartial } from '@core/typings';
  import React from 'react';
  import { ${interfaceName} } from '@core/blocks';
  import MjmlBlock, { MjmlBlockProps } from '@core/components/MjmlBlock';

  export type ${fileName}Props = RecursivePartial<${interfaceName}['data']> &
  RecursivePartial<${interfaceName}['attributes']> & {
    children?: MjmlBlockProps<${interfaceName}>['children'];
  };

  export function ${fileName}(props: ${fileName}Props) {
    return (
      <MjmlBlock
        attributes={omit(props, ['data', 'children'])}
        value={props.value}
        type={BasicType.${item.type.toUpperCase().replace('-', '_')}}
      >
        {props.children}
      </MjmlBlock>
    );
  }
  `;
  try {
    fs.mkdirSync(cwd + '/src/components');
  } catch (error) { }
  fs.writeFileSync(cwd + '/src/components/' + fileName + '.tsx', code);
  indexFileContent += `export {${fileName}} from './${fileName}'\n`;
});
Example #9
Source File: utils.ts    From aqualink-app with MIT License 6 votes vote down vote up
calculateSondeDataMeanValues = (
  metrics: SondeMetricsKeys[],
  timeSeriesData?: TimeSeriesData
) =>
  mapValues(pick(timeSeriesData, map(metrics, camelCase)), (data) =>
    meanBy(data?.sonde?.data, "value")
  )
Example #10
Source File: point_data.ts    From prism-frontend with MIT License 6 votes vote down vote up
queryParamsToString = (queryParams?: {
  [key: string]: string | { [key: string]: string };
}): string =>
  queryParams
    ? Object.entries(queryParams)
        .map(([key, value]) => {
          if (key === 'filters') {
            const filterValues = Object.entries(value)
              .map(([filterKey, filterValue]) => `${filterKey}=${filterValue}`)
              .join(',');

            return `filters=${filterValues}`;
          }
          return `${camelCase(key)}=${value}`;
        })
        .join('&')
    : ''
Example #11
Source File: camel-case.ts    From Adachi-BOT with MIT License 6 votes vote down vote up
export function toCamelCase( obj: any ): any {
	if ( Array.isArray( obj ) ) {
		return obj.map( el => toCamelCase( el ) );
	} else if ( obj !== null && typeof obj === "object" ) {
		return Object.keys( obj ).reduce( ( prev, cur ) => ( {
			...prev,
			[camelCase( cur )]: toCamelCase( obj[cur] )
		} ), {} );
	}
	
	return obj;
}
Example #12
Source File: tokensetsApi.ts    From index-ui with MIT License 6 votes vote down vote up
function formatComponents(components: any) {
  return components.map((component: any) => {
    const camelCasedComponent = Object.keys(component).reduce(
      (comp: any, k: string) => ({
        ...comp,
        [camelCase(k)]: component[k],
      }),
      {}
    )
    return camelCasedComponent
  })
}
Example #13
Source File: api-model-generator.ts    From selling-partner-api-sdk with MIT License 6 votes vote down vote up
export async function generateExportStatement(model: APIModel): Promise<string> {
  // Export all enums and interfaces
  const sourceFile = new Project({
    tsConfigFilePath: TS_CONFIG_FILE_PATH,
    libFolderPath: TS_LIB_FOLDER_PATH,
  }).getSourceFileOrThrow(`${model.outputPath}/${API_MODEL_FILE_NAME}`)

  const exports = [...sourceFile.getEnums(), ...sourceFile.getInterfaces()]
    .map(
      (declaration) =>
        `${declaration.getName()} as ${upperFirst(
          camelCase(model.dirname),
        )}${declaration.getName()}`,
    )
    .join(', ')

  return `export { ${exports} } from './${model.dirname}'`
}
Example #14
Source File: utils.ts    From prism-frontend with MIT License 6 votes vote down vote up
getLayerByKey = (layerKey: LayerKey): LayerType => {
  const rawDefinition = rawLayers[layerKey];

  const definition: { id: LayerKey; type: LayerType['type'] } = {
    id: layerKey,
    type: rawDefinition.type as LayerType['type'],
    ...mapKeys(rawDefinition, (v, k) => camelCase(k)),
  };

  const throwInvalidLayer = () => {
    throw new Error(
      `Found invalid layer definition for layer '${layerKey}'. Check console for more details.`,
    );
  };

  switch (definition.type) {
    case 'wms':
      if (checkRequiredKeys(WMSLayerProps, definition, true)) {
        return definition;
      }
      return throwInvalidLayer();
    case 'admin_level_data':
      if (checkRequiredKeys(AdminLevelDataLayerProps, definition, true)) {
        if (typeof (definition.adminLevel as unknown) !== 'number') {
          console.error(
            `admin_level in layer ${definition.id} isn't a number.`,
          );
          return throwInvalidLayer();
        }

        return definition;
      }
      return throwInvalidLayer();
    case 'impact':
      if (checkRequiredKeys(ImpactLayerProps, definition, true)) {
        return {
          ...definition,
          api: definition.api && parseStatsApiConfig(definition.api),
        };
      }
      return throwInvalidLayer();
    case 'point_data':
      if (checkRequiredKeys(PointDataLayerProps, definition, true)) {
        return definition;
      }
      return throwInvalidLayer();
    case 'boundary':
      if (checkRequiredKeys(BoundaryLayerProps, definition, true)) {
        return definition as BoundaryLayerProps;
      }
      return throwInvalidLayer();
    default:
      // doesn't do anything, but it helps catch any layer type cases we forgot above compile time via TS.
      // https://stackoverflow.com/questions/39419170/how-do-i-check-that-a-switch-block-is-exhaustive-in-typescript
      // eslint-disable-next-line no-unused-vars
      ((_: never) => {})(definition.type);
      throw new Error(
        `Found invalid layer definition for layer '${layerKey}' (Unknown type '${definition.type}'). Check config/layers.json.`,
      );
  }
}
Example #15
Source File: helpers.ts    From aqualink-app with MIT License 5 votes vote down vote up
mapMetrics = <T>(
  data: Partial<Record<MetricsKeys, T>>
): Partial<Record<Metrics, T>> =>
  mapKeys(pick(data, metricsKeysList), (_, key) => camelCase(key)) as Partial<
    Record<Metrics, T>
  >
Example #16
Source File: helpers.ts    From aqualink-app with MIT License 5 votes vote down vote up
parseLatestData = (data: LatestData[]): LatestDataASSofarValue => {
  if (!data || data.length === 0) return {};

  // Copying, sorting and filtering to keep spotter or latest data.
  const copy = [...data];
  const spotterValidityLimit = 12 * 60 * 60 * 1000; // 12 hours
  const validityDate = Date.now() - spotterValidityLimit;

  // sort data by timestamp ASCENDING but prioritize spotter data
  // eslint-disable-next-line fp/no-mutating-methods
  const sorted = copy.sort((x, y) => {
    // if spotter data is available and less than 12 hours old, use it.
    const xTime = new Date(x.timestamp).getTime();
    if (x.source === "spotter" && xTime > validityDate) {
      return +1;
    }
    const yTime = new Date(y.timestamp).getTime();
    if (y.source === "spotter" && yTime > validityDate) {
      return -1;
    }

    if (xTime > yTime) return +1;
    if (xTime < yTime) return -1;
    return 0;
  });

  // only keep spotter top/bottom temp for now
  const spotterTempWhitelist = new Set([
    "bottom_temperature",
    "top_temperature",
  ]);

  const filtered = sorted.filter(
    (value) =>
      value.source === "spotter" || !spotterTempWhitelist.has(value.metric)
  );

  // reduce the array, into a mapping, keeping only the latest data for each metric
  return filtered.reduce(
    (a, c) => ({
      ...a,
      [camelCase(c.metric)]: { timestamp: c.timestamp, value: c.value },
    }),
    {}
  );
}
Example #17
Source File: api-client-generator.ts    From selling-partner-api-sdk with MIT License 5 votes vote down vote up
generateAPIClientClassname = (apiClientFileName: string): string =>
  upperFirst(camelCase(apiClientFileName))
Example #18
Source File: settings-config-spec.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
describe("settings configuration properties", () => {
  let packageJsonSettings: Record<string, Setting>;

  before(() => {
    // Get the settings from the package.json
    const packageJsonPath = require.resolve(
      "vscode-ui5-language-assistant/package.json"
    );
    const packageJsonContent = readJsonSync(packageJsonPath);
    packageJsonSettings =
      packageJsonContent.contributes.configuration.properties;
  });

  it("default setting values in package.json have the correct type", () => {
    forEach(packageJsonSettings, (value, key) => {
      expect(
        typeof value.default,
        `Setting ${key} default value type does not match the setting's defined type`
      ).to.equal(value.type);
    });
  });

  it("settings in package.json are in sync with the settings package", () => {
    const defaultSettingsFromPackageJson = parseSettings(packageJsonSettings);
    const defaultSettings = getDefaultSettings();
    expect(
      defaultSettingsFromPackageJson,
      "settings from package.json don't match the default settings in the language server"
    ).to.deep.equal({
      UI5LanguageAssistant: defaultSettings,
    });
  });

  it("enums in package.json are in sync with the settings package", () => {
    const pkgJsonSettingsWithEnum = pickBy(packageJsonSettings, (_) =>
      has(_, "enum")
    );
    forEach(pkgJsonSettingsWithEnum, (pkgJsonSetting, settingsKey) => {
      const settingsModulePropName = camelCase(
        settingsKey.replace(
          /UI5LanguageAssistant.(\w+)\.(\w+)/,
          "valid $1 $2 values"
        )
      );
      const settingsModulePropValue = keys(
        settingsModule[settingsModulePropName]
      );
      const pkgJsonPropValue = pkgJsonSetting.enum;
      expect(settingsModulePropValue).to.deep.equalInAnyOrder(pkgJsonPropValue);
    });
  });

  it("use the correct logging configuration property name", () => {
    expect(packageJsonSettings[LOGGING_LEVEL_CONFIG_PROP]).to.exist;
    expect(
      packageJsonSettings[LOGGING_LEVEL_CONFIG_PROP].description
    ).to.include("logging");
  });

  type Setting = {
    scope: string;
    type: string;
    default: unknown;
    description: string;
    enum?: string[];
  };

  function parseSettings(properties: Record<string, Setting>): unknown {
    const defaultSettings = {};
    forEach(properties, (value, key) => {
      set(defaultSettings, key, value.default);
    });
    return defaultSettings;
  }
});
Example #19
Source File: options.ts    From pg-to-ts with MIT License 5 votes vote down vote up
transformTypeName(typename: string) {
    return this.options.camelCase ? upperFirst(camelCase(typename)) : typename;
  }
Example #20
Source File: options.ts    From pg-to-ts with MIT License 5 votes vote down vote up
transformColumnName(columnName: string) {
    return this.options.camelCase ? camelCase(columnName) : columnName;
  }
Example #21
Source File: options.ts    From pg-to-ts with MIT License 5 votes vote down vote up
DEFAULT_OPTIONS: OptionValues = {
  writeHeader: true,
  camelCase: false,
  datesAsStrings: false,
  prefixWithSchemaNames: false,
}
Example #22
Source File: run.tsx    From magic-js with MIT License 5 votes vote down vote up
template = (
  <Zombi<Props>
    name="create-magic-extension"
    templateRoot={path.resolve(__dirname, './template')}
    destinationRoot={path.resolve(__dirname, '../../../packages')}
    prompts={[
      {
        name: 'platform',
        message: 'What platform does the extension support?',
        type: 'select',
        choices: ['hybrid', 'web', 'react-native'],
      },

      {
        name: 'extName',
        message: 'What is the Extension name? (@magic-ext/[name])',
        type: 'input',
      },

      {
        name: 'extDescription',
        message: 'Please specify the description field for package.json',
        type: 'input',
      },

      {
        name: 'className',
        message: 'What is the exported Extension class name?',
        type: 'input',
      },
    ]}
  >
    {(props) => (
      <Directory name="@magic-ext">
        <Template
          name={props.extName}
          source={props.platform ?? 'hybrid'}
          data={{
            extNameCamelCase: camelCase(props.extName),
            cdnGlobalName: `Magic${props.className}`,
            magicSdkVersion: `^${environment.WEB_VERSION}`,
            magicSdkReactVersion: `^${environment.REACT_NATIVE_VERSION}`,
            magicSdkCommonsVersion: `^${require('../../../packages/@magic-sdk/commons/package.json').version}`,
          }}
        />
      </Directory>
    )}
  </Zombi>
)
Example #23
Source File: model-factory.ts    From ts-japi with Apache License 2.0 5 votes vote down vote up
ModelFactory = {
 addArrayAttribute<T extends typeof Base, U extends typeof Base>(
  name: string,
  target: T,
  source: U
 ) {
  const getterName = `get${capitalize(camelCase(name))}`;
  target.afterRemoveHook = target.afterRemoveHook ?? [];
  target.beforeSaveHook = target.beforeSaveHook ?? [];
  target.prototype = target.prototype ?? ({} as any);
  (target.prototype as any)[getterName] = function <Target>(this: Target) {
   return findAllExisting((this as any)[name], (id: string) => source.find(id));
  };
  target.afterRemoveHook.push(<Target, Source extends Base>(model: Target) => {
   (model as any)[getterName]().map((m: Source) => source.remove(m));
  });
  target.beforeSaveHook.push(<Target>(model: Target) => {
   findAllExisting((model as any)[name], (id: string) => source.find(id));
  });
 },
 addSingleAttribute<T extends typeof Base, U extends typeof Base>(
  name: string,
  othername: string,
  target: T,
  source: U
 ) {
  const getterName = `get${capitalize(camelCase(name))}`;
  target.beforeSaveHook = target.beforeSaveHook ?? [];
  target.prototype = target.prototype ?? ({} as any);
  (target.prototype as any)[getterName] = function <Target>(this: Target) {
   return source.find((this as any)[name]);
  };
  target.beforeSaveHook.push(<Target extends Base>(model: Target) => {
   const sourceModel = (model as any)[getterName]();
   if (!sourceModel) throw new Error(`no ${name}`);
   pushIfNotExists(sourceModel[othername], model.id, (id) => id === model.id);
  });
 },
 createModel<T extends typeof Base>(model: T) {
  model.storage = [];
  model.find = function (this: T, id: string) {
   if (this.beforeFindHook) this.beforeFindHook.forEach((hook) => hook(id));
   const result = this.storage.find((u) => u.id === id);
   if (this.afterFindHook) this.afterFindHook.forEach((hook) => hook(id));
   return result;
  };
  model.remove = function <U extends Base>(this: T, obj: U) {
   if (this.beforeRemoveHook) this.beforeRemoveHook.forEach((hook) => hook(obj));
   let idx = this.storage.findIndex((u) => u.id === obj.id);
   if (typeof idx === "number") {
    delete this.storage[idx];
   }
   if (this.afterRemoveHook) this.afterRemoveHook.forEach((hook) => hook(obj));
   return obj;
  };
  model.save = function <U extends Base>(this: T, model: U) {
   if (this.beforeSaveHook) this.beforeSaveHook.forEach((hook) => hook(model));
   pushIfNotExists(this.storage, model, (m) => m.id === model.id);
   if (this.afterSaveHook) this.afterSaveHook.forEach((hook) => hook(model));
   return model;
  };
 },
}
Example #24
Source File: pascal-case.ts    From prisma-nestjs-graphql with MIT License 5 votes vote down vote up
export function pascalCase(string: string) {
  return startCase(camelCase(string)).replace(/ /g, '');
}
Example #25
Source File: index.tsx    From aqualink-app with MIT License 4 votes vote down vote up
MultipleSensorsCharts = ({
  site,
  pointId,
  surveysFiltered,
  disableGutters,
  displayOceanSenseCharts,
}: MultipleSensorsChartsProps) => {
  const classes = useStyles();
  const dispatch = useDispatch();
  const getQueryParam = useQueryParams();
  const [startDateParam, endDateParam, initialChart] = [
    "start",
    "end",
    "chart",
  ].map(getQueryParam);
  const initialStart =
    startDateParam && isISODate(startDateParam) ? startDateParam : undefined;
  const initialEnd =
    endDateParam && isISODate(endDateParam) ? endDateParam : undefined;
  const granularDailyData = useSelector(siteGranularDailyDataSelector);
  const timeSeriesData = useSelector(siteTimeSeriesDataSelector);
  const oceanSenseData = useSelector(siteOceanSenseDataSelector);
  const latestData = useSelector(latestDataSelector);
  const { bottomTemperature, topTemperature } = timeSeriesData || {};
  const { hobo: hoboBottomTemperature } = bottomTemperature || {};
  const timeSeriesDataRanges = useSelector(siteTimeSeriesDataRangeSelector);
  const { hobo: hoboBottomTemperatureRange } =
    timeSeriesDataRanges?.bottomTemperature || {};
  const rangesLoading = useSelector(siteTimeSeriesDataRangeLoadingSelector);
  const [pickerEndDate, setPickerEndDate] = useState<string>();
  const [pickerStartDate, setPickerStartDate] = useState<string>();
  const [endDate, setEndDate] = useState<string>();
  const [startDate, setStartDate] = useState<string>();
  const [pickerErrored, setPickerErrored] = useState(false);
  const [range, setRange] = useState<RangeValue>(
    initialStart || initialEnd ? "custom" : "one_month"
  );
  const history = useHistory();

  const today = localizedEndOfDay(undefined, site.timezone);

  const hasSpotterData = Boolean(
    bottomTemperature?.spotter?.data?.[1] || topTemperature?.spotter?.data?.[1]
  );

  const hasSondeData = Boolean(
    latestData?.some((data) => data.source === "sonde")
  );

  const hasMetlogData = Boolean(
    latestData?.some((data) => data.source === "metlog")
  );

  const chartStartDate = startDate || subtractFromDate(today, "week");
  const chartEndDate = moment
    .min(
      moment(),
      moment(endDate)
        .tz(site.timezone || "UTC")
        .endOf("day")
    )
    .toISOString();

  const hasOceanSenseId = Boolean(oceanSenseConfig?.[site.id]);

  const tempAnalysisDatasets = generateTempAnalysisDatasets(
    granularDailyData,
    timeSeriesData?.bottomTemperature?.spotter?.data,
    timeSeriesData?.topTemperature?.spotter?.data,
    hoboBottomTemperature?.data,
    site.historicalMonthlyMean,
    startDate,
    endDate,
    chartStartDate,
    chartEndDate,
    site.timezone,
    site.depth
  );

  const spotterMetricDataset = (metric: Metrics) => {
    const { unit, convert } = spotterConfig[metric] || {};

    return generateMetricDataset(
      "SENSOR",
      timeSeriesData?.[metric]?.spotter?.data?.map((item) => ({
        ...item,
        value: convert ? convert * item.value : item.value,
      })) || [],
      unit || "",
      SPOTTER_METRIC_DATA_COLOR,
      chartStartDate,
      chartEndDate,
      site.timezone
    );
  };

  const sondeDatasets = () =>
    hasSondeData
      ? sortBy(getPublicSondeMetrics(), (key) => getSondeConfig(key).order)
          .filter(
            (key) =>
              timeSeriesData?.[camelCase(key) as Metrics]?.sonde?.data?.length
          )
          .map((key) => {
            const { data, surveyPoint } =
              timeSeriesData?.[camelCase(key) as Metrics]?.sonde || {};
            const { title, units } = getSondeConfig(key);

            return {
              key,
              title,
              surveyPoint,
              dataset: generateMetricDataset(
                "SENSOR",
                data || [],
                units,
                SONDE_DATA_COLOR,
                chartStartDate,
                chartEndDate,
                site.timezone
              ),
            };
          })
      : [];

  const metlogDatasets = () =>
    hasMetlogData
      ? sortBy(getPublicMetlogMetrics(), (key) => getMetlogConfig(key).order)
          .filter(
            (key) =>
              timeSeriesData?.[camelCase(key) as Metrics]?.metlog?.data?.length
          )
          .map((key) => {
            const { data, surveyPoint } =
              timeSeriesData?.[camelCase(key) as Metrics]?.metlog || {};
            const { title, units, convert } = getMetlogConfig(key);

            return {
              key,
              title,
              surveyPoint,
              dataset: generateMetricDataset(
                "SENSOR",
                (data || []).map((item) => ({
                  ...item,
                  value: isNumber(convert) ? item.value * convert : item.value,
                })),
                units,
                METLOG_DATA_COLOR,
                chartStartDate,
                chartEndDate,
                site.timezone
              ),
            };
          })
      : [];

  // Scroll to the chart defined by the initialChart query param.
  useEffect(() => {
    if (initialChart) {
      const chartElement = document.getElementById(initialChart);
      chartElement?.scrollIntoView();
    }
  }, [initialChart]);

  // Set pickers initial values once the range request is completed
  useEffect(() => {
    if (!rangesLoading && !pickerStartDate && !pickerEndDate) {
      const { maxDate } = hoboBottomTemperatureRange?.data?.[0] || {};
      const localizedMaxDate = localizedEndOfDay(maxDate, site.timezone);
      const pastOneMonth = moment(
        subtractFromDate(localizedMaxDate || today, "month", 1)
      )
        .tz(site.timezone || "UTC")
        .startOf("day")
        .toISOString();
      setPickerStartDate(
        initialStart
          ? zonedTimeToUtc(initialStart, site.timezone || "UTC").toISOString()
          : utcToZonedTime(pastOneMonth, site.timezone || "UTC").toISOString()
      );
      setPickerEndDate(
        initialEnd
          ? zonedTimeToUtc(initialEnd, site.timezone || "UTC").toISOString()
          : utcToZonedTime(
              localizedMaxDate || today,
              site.timezone || "UTC"
            ).toISOString()
      );
    }
  }, [
    hoboBottomTemperatureRange,
    initialEnd,
    initialStart,
    pickerStartDate,
    pickerEndDate,
    rangesLoading,
    site.timezone,
    today,
  ]);

  // Get time series data
  useEffect(() => {
    if (
      pickerStartDate &&
      pickerEndDate &&
      isBefore(pickerStartDate, pickerEndDate)
    ) {
      const siteLocalStartDate = setTimeZone(
        new Date(pickerStartDate),
        site.timezone
      );

      const siteLocalEndDate = setTimeZone(
        new Date(pickerEndDate),
        site.timezone
      );

      dispatch(
        siteTimeSeriesDataRequest({
          siteId: `${site.id}`,
          pointId,
          start: siteLocalStartDate,
          end: siteLocalEndDate,
          metrics: hasSondeData || hasMetlogData ? undefined : DEFAULT_METRICS,
          hourly:
            moment(siteLocalEndDate).diff(moment(siteLocalStartDate), "days") >
            2,
        })
      );

      if (hasOceanSenseId) {
        dispatch(
          siteOceanSenseDataRequest({
            sensorID: oceanSenseConfig[site.id],
            startDate: siteLocalStartDate,
            endDate: siteLocalEndDate,
            latest: false,
          })
        );
      }
    }
  }, [
    dispatch,
    hasMetlogData,
    hasOceanSenseId,
    hasSondeData,
    pickerEndDate,
    pickerStartDate,
    pointId,
    site.id,
    site.timezone,
  ]);

  // Set chart start/end dates based on data received
  useEffect(() => {
    const pickerLocalEndDate = new Date(
      setTimeZone(
        new Date(moment(pickerEndDate).format("MM/DD/YYYY")),
        site?.timezone
      )
    ).toISOString();
    const pickerLocalStartDate = new Date(
      setTimeZone(
        new Date(moment(pickerStartDate).format("MM/DD/YYYY")),
        site?.timezone
      )
    ).toISOString();

    const [minDataDate, maxDataDate] = findDataLimits(
      site.historicalMonthlyMean,
      granularDailyData,
      timeSeriesData,
      pickerLocalStartDate,
      localizedEndOfDay(pickerLocalEndDate, site.timezone)
    );

    setStartDate(
      minDataDate
        ? moment
            .max(moment(minDataDate), moment(pickerLocalStartDate))
            .toISOString()
        : pickerLocalStartDate
    );

    setEndDate(
      maxDataDate
        ? moment
            .min(moment(maxDataDate), moment(pickerLocalEndDate).endOf("day"))
            .toISOString()
        : moment(pickerLocalEndDate).endOf("day").toISOString()
    );
  }, [granularDailyData, pickerEndDate, pickerStartDate, site, timeSeriesData]);

  useEffect(() => {
    if (pickerStartDate && pickerEndDate) {
      // eslint-disable-next-line fp/no-mutating-methods
      history.push({
        search: `?start=${pickerStartDate.split("T")[0]}&end=${
          pickerEndDate.split("T")[0]
        }`,
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [history, pickerEndDate, pickerStartDate, site.timezone]);

  // Set picker error
  useEffect(() => {
    if (pickerStartDate && pickerEndDate) {
      setPickerErrored(!isBefore(pickerStartDate, pickerEndDate));
    }
  }, [pickerEndDate, pickerStartDate]);

  const dataForCsv = [
    ...tempAnalysisDatasets.map((dataset) => ({
      name: `${dataset.metric || "unknownMetric"}_${
        dataset.source || "unknownSource"
      }`,
      values: dataset.data,
    })),
    ...Object.entries(spotterConfig).map(([key]) => {
      const dataset = spotterMetricDataset(key as Metrics);
      return {
        name: `${key}_spotter`,
        values: dataset.data,
      };
    }),
    ...Object.entries(constructOceanSenseDatasets(oceanSenseData)).map(
      ([key, item]) => {
        const dataset = generateMetricDataset(
          key,
          item.data,
          item.unit,
          OCEAN_SENSE_DATA_COLOR,
          chartStartDate,
          chartEndDate,
          site.timezone
        );
        return {
          name: `${camelCase(item.title.split(" ")[0])}`,
          values: dataset.data,
        };
      }
    ),
    ...sondeDatasets().map(({ title, dataset }) => ({
      name: `${title} ${dataset.label}`,
      values: dataset.data,
    })),
  ].filter((x) => x.values.length > 0);

  const onRangeChange = (value: RangeValue) => {
    const { minDate, maxDate } = hoboBottomTemperatureRange?.data?.[0] || {};
    const localizedMinDate = new Date(
      moment(minDate)
        .tz(site.timezone || "UTC")
        .format("MM/DD/YYYY")
    ).toISOString();
    const localizedMaxDate = new Date(
      moment(maxDate)
        .tz(site.timezone || "UTC")
        .format("MM/DD/YYYY")
    ).toISOString();
    setRange(value);
    switch (value) {
      case "one_month":
        setPickerEndDate(moment(localizedMaxDate).endOf("day").toISOString());
        setPickerStartDate(subtractFromDate(localizedMaxDate, "month", 1));
        break;
      case "one_year":
        setPickerEndDate(moment(localizedMaxDate).endOf("day").toISOString());
        setPickerStartDate(subtractFromDate(localizedMaxDate, "year"));
        break;
      case "max":
        setPickerEndDate(moment(localizedMaxDate).endOf("day").toISOString());
        setPickerStartDate(localizedMinDate);
        break;
      default:
        break;
    }
  };

  const onPickerDateChange = (type: "start" | "end") => (date: Date | null) => {
    const time = date?.getTime();
    if (date && time && !isNaN(time)) {
      const dateString = date.toISOString();
      setRange("custom");
      switch (type) {
        case "start":
          // Set picker start date only if input date is after zero time
          if (
            moment(dateString)
              .startOf("day")
              .isSameOrAfter(moment(0).startOf("day"))
          ) {
            setPickerStartDate(moment(dateString).startOf("day").toISOString());
          }
          break;
        case "end":
          // Set picker end date only if input date is before today
          if (
            moment(dateString)
              .endOf("day")
              .isSameOrBefore(moment().endOf("day"))
          ) {
            setPickerEndDate(moment(dateString).endOf("day").toISOString());
          }
          break;
        default:
          break;
      }
    }
  };

  return (
    <Container
      disableGutters={disableGutters}
      className={classes.chartWithRange}
    >
      <div className={classes.buttonWrapper}>
        <DownloadCSVButton
          data={dataForCsv}
          startDate={pickerStartDate}
          endDate={pickerEndDate}
          siteId={site.id}
          pointId={pointId}
          className={classes.button}
        />
      </div>
      <ChartWithCard
        id="temperature"
        range={range}
        onRangeChange={onRangeChange}
        disableMaxRange={!hoboBottomTemperatureRange?.data?.[0]}
        chartTitle="TEMPERATURE ANALYSIS"
        availableRanges={[
          {
            name: "Spotter",
            data: timeSeriesDataRanges?.bottomTemperature?.spotter?.data,
          },
          {
            name: "HOBO",
            data: timeSeriesDataRanges?.bottomTemperature?.hobo?.data,
          },
        ]}
        timeZone={site.timezone}
        chartWidth={findChartWidth(tempAnalysisDatasets)}
        site={site}
        datasets={tempAnalysisDatasets}
        pointId={pointId ? parseInt(pointId, 10) : undefined}
        pickerStartDate={pickerStartDate || subtractFromDate(today, "week")}
        pickerEndDate={pickerEndDate || today}
        chartStartDate={chartStartDate}
        chartEndDate={chartEndDate}
        onStartDateChange={onPickerDateChange("start")}
        onEndDateChange={onPickerDateChange("end")}
        isPickerErrored={pickerErrored}
        areSurveysFiltered={surveysFiltered}
      />
      {hasSpotterData &&
        Object.entries(spotterConfig).map(([key, { title }]) => (
          <Box mt={4} key={title}>
            <ChartWithCard
              datasets={[spotterMetricDataset(key as Metrics)]}
              id={key}
              range={range}
              onRangeChange={onRangeChange}
              disableMaxRange={!hoboBottomTemperatureRange?.data?.[0]}
              chartTitle={title}
              availableRanges={[
                {
                  name: "Spotter",
                  data: timeSeriesDataRanges?.[key as Metrics]?.spotter?.data,
                },
              ]}
              timeZone={site.timezone}
              showRangeButtons={false}
              chartWidth="large"
              site={site}
              pickerStartDate={
                pickerStartDate || subtractFromDate(today, "week")
              }
              pickerEndDate={pickerEndDate || today}
              chartStartDate={chartStartDate}
              chartEndDate={chartEndDate}
              onStartDateChange={onPickerDateChange("start")}
              onEndDateChange={onPickerDateChange("end")}
              isPickerErrored={pickerErrored}
              showDatePickers={false}
              hideYAxisUnits
              cardColumnJustification="flex-start"
            />
          </Box>
        ))}
      {displayOceanSenseCharts &&
        hasOceanSenseId &&
        Object.entries(constructOceanSenseDatasets(oceanSenseData)).map(
          ([key, item]) => (
            <Box mt={4} key={item.title}>
              <ChartWithCard
                datasets={[
                  generateMetricDataset(
                    key,
                    item.data,
                    item.unit,
                    OCEAN_SENSE_DATA_COLOR,
                    chartStartDate,
                    chartEndDate,
                    site.timezone
                  ),
                ]}
                id={item.id}
                range={range}
                onRangeChange={onRangeChange}
                disableMaxRange={!hoboBottomTemperatureRange?.data?.[0]}
                chartTitle={item.title}
                timeZone={site.timezone}
                showRangeButtons={false}
                chartWidth="large"
                site={site}
                pickerStartDate={
                  pickerStartDate || subtractFromDate(today, "week")
                }
                pickerEndDate={pickerEndDate || today}
                chartStartDate={chartStartDate}
                chartEndDate={chartEndDate}
                onStartDateChange={onPickerDateChange("start")}
                onEndDateChange={onPickerDateChange("end")}
                isPickerErrored={pickerErrored}
                showDatePickers={false}
                hideYAxisUnits
                cardColumnJustification="flex-start"
              />
            </Box>
          )
        )}
      {sondeDatasets().map(({ key, title, surveyPoint, dataset }) => (
        <Box mt={4} key={key}>
          <ChartWithCard
            datasets={[dataset]}
            id={key}
            range={range}
            onRangeChange={onRangeChange}
            disableMaxRange={!hoboBottomTemperatureRange?.data?.[0]}
            chartTitle={title}
            availableRanges={[
              {
                name: "Sonde",
                data: timeSeriesDataRanges?.[camelCase(key) as Metrics]?.sonde
                  ?.data,
              },
            ]}
            timeZone={site.timezone}
            showRangeButtons={false}
            chartWidth="large"
            site={site}
            pickerStartDate={pickerStartDate || subtractFromDate(today, "week")}
            pickerEndDate={pickerEndDate || today}
            chartStartDate={chartStartDate}
            chartEndDate={chartEndDate}
            onStartDateChange={onPickerDateChange("start")}
            onEndDateChange={onPickerDateChange("end")}
            isPickerErrored={pickerErrored}
            showDatePickers={false}
            surveyPoint={surveyPoint}
            hideYAxisUnits
            cardColumnJustification="flex-start"
          />
        </Box>
      ))}
      {metlogDatasets().map(({ key, title, surveyPoint, dataset }) => (
        <Box mt={4} key={key}>
          <ChartWithCard
            datasets={[dataset]}
            id={key}
            range={range}
            onRangeChange={onRangeChange}
            disableMaxRange={!hoboBottomTemperatureRange?.data?.[0]}
            chartTitle={title}
            availableRanges={[
              {
                name: "Meteorological",
                data: timeSeriesDataRanges?.[camelCase(key) as Metrics]?.metlog
                  ?.data,
              },
            ]}
            timeZone={site.timezone}
            showRangeButtons={false}
            chartWidth="large"
            site={site}
            pickerStartDate={pickerStartDate || subtractFromDate(today, "week")}
            pickerEndDate={pickerEndDate || today}
            chartStartDate={chartStartDate}
            chartEndDate={chartEndDate}
            onStartDateChange={onPickerDateChange("start")}
            onEndDateChange={onPickerDateChange("end")}
            isPickerErrored={pickerErrored}
            showDatePickers={false}
            surveyPoint={surveyPoint}
            hideYAxisUnits
            cardColumnJustification="flex-start"
          />
        </Box>
      ))}
    </Container>
  );
}
Example #26
Source File: DestinationEditorTransform.tsx    From jitsu with MIT License 4 votes vote down vote up
DestinationEditorTransform = ({
  destinationData,
  destinationReference,
  form,
  configForm,
  mappingForm,
  handleTouchAnyField,
}: Props) => {
  const handleChange = debounce(handleTouchAnyField, 500)
  const [documentationVisible, setDocumentationVisible] = useState(false)
  const templateVarsSuggestions = Object.entries(configForm.getFieldsValue())
    .filter(v => v[0].startsWith("_formData._"))
    .map(v => [v[0].replace("_formData._", ""), v[1]])
    .map(v => `declare const ${v[0]} = "${v[1]}"\n`)
    .join()

  return (
    <>
      <TabDescription>
        <p>
          Use the power of Javascript to modify incoming event object, replace it with a completely new event or produce
          multiple events based on incoming data.
          <br />
          Also, you can use <b>Transform</b> to assign Data Warehouse specific SQL types for object fields, set the
          destination table name for each event or to skip the event altogether.{" "}
          <a onClick={() => setDocumentationVisible(true)}>Open Documentation →</a>
          <br />
          <b>Transform</b> effectively replaces <b>Mappings</b> – both features cannot work together.
        </p>
      </TabDescription>
      <Form name="destination-config" form={form} autoComplete="off" onChange={handleChange}>
        <ConfigurableFieldsForm
          handleTouchAnyField={handleTouchAnyField}
          fieldsParamsList={[
            {
              id: "_transform_enabled",
              displayName: "Enable Javascript Transformation",
              defaultValue: !destinationData._mappings?._mappings,
              required: false,
              omitFieldRule: cfg =>
                destinationsReferenceMap[destinationData._type].defaultTransform.length > 0 &&
                !destinationData._mappings?._mappings,
              type: booleanType,
              validator: (rule, value) => {
                if (value && mappingForm?.getFieldValue("_mappings._mappings")?.length > 0) {
                  return Promise.reject(
                    "Transform cannot work with configured mappings. Please remove all mappings first."
                  )
                }
                return Promise.resolve()
              },
              bigField: true,
            },
            {
              id: "_transform",
              codeSuggestions: `${templateVarsSuggestions}declare const destinationId = "${destinationData._uid}";
declare const destinationType = "${destinationData._type}";
${[destinationData._type, "segment"]
  .map(type => `declare function ${camelCase("to_" + type)}(event: object): object`)
  .join("\n")}`,
              displayName: "Javascript Transformation",
              defaultValue: !destinationData._mappings?._mappings
                ? destinationsReferenceMap[destinationData._type].defaultTransform
                : "",
              required: false,
              jsDebugger: "object",
              type: jsType,
              bigField: true,
            },
          ]}
          form={form}
          extraForms={[configForm, mappingForm]}
          initialValues={destinationData}
        />
      </Form>

      <Drawer
        title={<h2>Transform Examples</h2>}
        placement="right"
        closable={true}
        onClose={() => setDocumentationVisible(false)}
        width="50%"
        visible={documentationVisible}
      >
        <div className={styles.documentation}>
          <Collapse defaultActiveKey={["overview"]} ghost>
            <Collapse.Panel header={<div className="font-bold">Overview</div>} key="overview">
              <p>
                You can use modern javascript language features and built-in functions to transform an incoming event.
                <br />
                Jitsu puts incoming event as a global variable: <code>$</code>
                <br />
              </p>
              <p>
                Provided javascript must return:
                <ul>
                  <li>
                    <b>single object</b> - modified incoming event or completely new object{" "}
                  </li>
                  <li>
                    <b>array of objects</b> - a single incoming event will result in multiple events in destinations
                  </li>
                  <li>
                    <b>null</b> - to skip event from processing
                  </li>
                </ul>
              </p>
              <p>
                To override the destination table, you need to add a special property <code>JITSU_TABLE_NAME</code> to
                the resulting events.
              </p>
              <p>
                To override the destination SQL column type for a specific object field, you need to add an extra
                property with the special prefix <code>__sql_type_</code> added to the name of a field to resulting
                events. E.g.: <code>__sql_type_utc_time: "date"</code> sets SQL type <b>date</b> for column{" "}
                <b>utc_time</b>
              </p>
              <p>See more bellow.</p>
            </Collapse.Panel>
            <Collapse.Panel header={<div className="font-bold">Modify incoming event</div>} key="modify">
              <p>
                Javascript spread operator allows making a copy of an incoming event while applying some changes in just
                a few lines of code:
              </p>
              <CodeSnippet size={"large"} language={"javascript"}>{`return {...$,
    new_property: $.event_type
}`}</CodeSnippet>
              <p>Add property to user object:</p>
              <CodeSnippet size={"large"} language={"javascript"}>{`return {...$, 
        user: {...$.user, state: "active"}
        }`}</CodeSnippet>
            </Collapse.Panel>
            <Collapse.Panel header={<div className="font-bold">Build new event</div>} key="new">
              <p>Collect some user properties to the new object:</p>
              <CodeSnippet size={"large"} language={"javascript"}>{`return {
  properties: [
    {
      property: "email",
      value: $.user?.email
    },
    {
      property: "language",
      value: $.user_language
    }
  ]
}`}</CodeSnippet>

              <p>Put an original event as a string payload:</p>
              <CodeSnippet size={"large"} language={"javascript"}>{`return {
        "event_type": "POST event",
        "payload": JSON.stringify($)
}`}</CodeSnippet>
            </Collapse.Panel>
            <Collapse.Panel header={<div className="font-bold">Produce multiple events</div>} key="multiple">
              <p>Produce multiple purchase events from a single shopping cart event:</p>
              <CodeSnippet
                size={"large"}
                language={"javascript"}
              >{`if ($.event_type == "conversion" && $.products?.length > 0) {
        let results = []
        for (const product of $.products) {
                results.push({
                        event_type: "purchase",
                        product_id: product.id,
                        price: product.price
                })
        }
        return results
} else {
        //skip events without any purchase
        return null
}`}</CodeSnippet>
            </Collapse.Panel>
            <Collapse.Panel header={<div className="font-bold">Override destination table</div>} key="tablename">
              <p>Using Javascript spread operator:</p>
              <CodeSnippet
                size={"large"}
                language={"javascript"}
              >{`return {...$, JITSU_TABLE_NAME: "new_table_name"}`}</CodeSnippet>
              <p>Conventional way:</p>
              <CodeSnippet size={"large"} language={"javascript"}>{`$.JITSU_TABLE_NAME = "new_table_name"
return $`}</CodeSnippet>
            </Collapse.Panel>
            <Collapse.Panel header={<div className="font-bold">Override SQL column type</div>} key="sql_type">
              <p>Set simple SQL types:</p>
              <CodeSnippet size={"large"} language={"javascript"}>{`return {...$, 
    event_date: $.utc_time,                               
    __sql_type_event_date: "date",
    event_time: $.utc_time,
    __sql_type_event_time: "time"
}`}</CodeSnippet>
              <p>
                Sql types with extra parameters:
                <br />
                Some Data Warehouses support extra parameters for column types during table creation.
                <br />
                For such cases, Transform uses the following syntax to provide data type and column type separately:
              </p>
              <CodeSnippet size={"large"} language={"javascript"}>{`return {...$, 
    title: $.page_title,                               
    __sql_type_title: ["varchar(256)", "varchar(256) encode zstd"]
}`}</CodeSnippet>
            </Collapse.Panel>
            <Collapse.Panel
              header={<div className="font-bold">Predefined constants and functions</div>}
              key="predefined"
            >
              <p>
                Transform comes with predefined constants: <code>destinationId</code> and <code>destinationType</code>{" "}
                that can be used to enrich your data:
              </p>
              <CodeSnippet size={"large"} language={"javascript"}>{`return {...$, 
    destination_id: destinationId,
    destination_type: destinationType,
}`}</CodeSnippet>
              <p>
                Also <code>toSegment(event)</code> function is available to set up{" "}
                <a href={"https://jitsu.com/docs/other-features/segment-compatibility"} target={"_blank"}>
                  Segment Compatibility
                </a>
                :
              </p>
              <CodeSnippet size={"large"} language={"javascript"}>{`return toSegment($)`}</CodeSnippet>
            </Collapse.Panel>
          </Collapse>
        </div>
      </Drawer>
    </>
  )
}
Example #27
Source File: resolver.ts    From one-platform with MIT License 4 votes vote down vote up
LighthouseAuditResolver = {
  LHLeaderBoardCategory: {
    PWA: 'category_pwa_median',
    SEO: 'category_seo_median',
    BEST_PRACTICES: 'category_best-practices_median',
    ACCESSIBILITY: 'category_accessibility_median',
    PERFORMANCE: 'category_performance_median',
    OVERALL: 'overall',
  },
  Query: {
    async listLHProjects(root: any, args: any) {
      return lhDbManager.getAllProjects(args);
    },
    async listProjectLHReport(root: any, args: any) {
      const buildScores = await lhDbManager.getLHScores(args.projectID, [
        args.buildID,
      ]);
      return buildScores[args.buildID];
    },
    async verifyLHProjectDetails(root: any, args: any) {
      return lhci.fetchProjectDetails(
        args.serverBaseUrl || process.env.SERVER_BASE_URL,
        args.buildToken,
      );
    },
    async listLHProjectBuilds(root: any, args: any) {
      const projectBuilds = await lhDbManager.getAllBuilds(
        args.projectId,
        args.branch,
        args.limit,
      );
      const lhScore = await lhDbManager.getLHScores(
        args.projectId,
        projectBuilds.map(({ id }: any) => id),
      );

      // eslint-disable-next-line no-param-reassign
      projectBuilds.forEach((build: any, index: number) => {
        (projectBuilds[index] as any).score = lhScore[build.id];
      });
      return projectBuilds;
    },
    async listLHProjectBranches(root: any, args: any) {
      return lhDbManager.getAllBranches(args.projectId, args);
    },
    async listLHLeaderboard(root: any, args: any) {
      return lhDbManager.getLeaderBoard(args);
    },
    async getLHRankingOfAProjectBranch(root: any, args: any) {
      return lhDbManager.getLHRankingOfAProjectBranch(args);
    },
  },
  Mutation: {
    async createLHProject(root: any, args: any) {
      const project = {
        name: args.project.name,
        baseBranch: args.project.baseBranch,
        externalUrl: args.project.externalUrl,
      };
      return lhci.createLHProject(project);
    },
    auditWebsite(root: any, args: any) {
      const lhciBuildContextHash = new Date()
        .getTime()
        .toString(16)
        .split('')
        .reverse()
        .join('');
      pubsub
        .publish('AUTORUN', {
          autorun: `${lhciBuildContextHash}Started the Audit`,
        })
        .catch((err) => Logger.error(err));
      (async () => {
        const chrome = await chromeLauncher.launch({
          chromeFlags: [
            '--headless',
            ' --no-sandbox',
            '--ignore-certificate-errors',
          ],
          preset: `${args.property.preset || 'perf'}`,
        });
        const result = await lighthouse(args.property.sites, {
          logLevel: 'info',
          verbose: true,
          output: 'json',
          onlyCategories: [
            'performance',
            'accessibility',
            'best-practices',
            'seo',
            'pwa',
          ],
          port: chrome.port,
        });
        const data: any = {};
        Object.keys(result.lhr.categories).forEach((category: any) => {
          data[camelCase(category)] = Math.trunc(
            result.lhr.categories[category].score * 100,
          );
        });
        pubsub
          .publish('AUTORUN', {
            autorun: `${lhciBuildContextHash}Results:${JSON.stringify(data)}`,
          })
          .catch((error: Error) => Logger.error(error));
        pubsub
          .publish('AUTORUN', {
            autorun: `${lhciBuildContextHash}Audit Completed`,
          })
          .catch((err: Error) => Logger.error(err));
        await chrome.kill();
      })();
      return lhciBuildContextHash;
    },
  },
  Subscription: {
    autorun: {
      subscribe: () => pubsub.asyncIterator('AUTORUN'),
    },
  },
}