File

libs/nx/src/generators/journey-src/lib/add-lib-assets-to-build-target/add-lib-assets-to-build-target.ts

Index

Properties

Properties

glob
Type string
input
Type string
output
Type string
import { LibraryConfiguration } from '@allianz/taly-core/schemas';
import {
  joinPathFragments,
  logger,
  readProjectConfiguration,
  Tree,
  updateProjectConfiguration
} from '@nx/devkit';

interface AssetPattern {
  glob: string;
  input: string;
  output: string;
}

interface AssetPatternWithRoot extends AssetPattern {
  libraryRoot: string;
}

export function addLibAssetsToBuildTarget(
  tree: Tree,
  projectName: string,
  libraries: LibraryConfiguration[]
) {
  const project = readProjectConfiguration(tree, projectName);
  const assetConfigsFromLibs = createAssetConfigsFromLibs(tree, libraries);

  if (assetConfigsFromLibs?.length === 0) {
    return;
  }

  const buildTarget = project.targets?.['build-generated-app'];

  if (!buildTarget) {
    logger.warn(
      `⚠️ No "build-generated-app" target in project "${projectName}". Cannot add library assets to the "build-generated-app" target. Please consider adding a "build-generated-app" target.`
    );
    return;
  }

  const existingAssets: (string | AssetPattern)[] = buildTarget.options?.['assets'] ?? [];

  const { assetsToAdd, assetsToUpdate } = getMismatchedAssets(existingAssets, assetConfigsFromLibs);

  if (assetsToAdd.length === 0 && assetsToUpdate.length === 0) {
    return;
  }

  let updatedAssets = structuredClone(existingAssets);

  // remove all the assets from target config that are going to be updated with new values
  if (assetsToUpdate.length > 0) {
    updatedAssets = updatedAssets.map((existingAsset) => {
      if (typeof existingAsset === 'string') return existingAsset;

      // we only want to keep the assets that don't need to be updated
      const assetToUpdateWithRoot = assetsToUpdate.find(({ libraryRoot }) =>
        existingAsset.input.includes(libraryRoot)
      );

      if (!assetToUpdateWithRoot) return existingAsset;

      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { libraryRoot, ...assetToUpdate } = assetToUpdateWithRoot;
      return assetToUpdate;
    });
  }

  // add new assets while removing the `libraryRoot` property
  updatedAssets.push(
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    ...assetsToAdd.map(({ libraryRoot, ...rest }) => rest)
  );

  buildTarget.options ??= {};
  buildTarget.options['assets'] = updatedAssets;

  updateProjectConfiguration(tree, projectName, project);

  logger.info(
    "This updated your project's build target configuration with some missing/outdated library assets. Please make sure to commit these changes."
  );
}

function getMismatchedAssets(
  existingAssets: (string | AssetPattern)[],
  assetConfigsFromLibs: AssetPatternWithRoot[]
) {
  const existingAssetsObjects: AssetPattern[] = existingAssets.filter(
    (asset): asset is AssetPattern => typeof asset !== 'string'
  );

  const assetsToAdd = assetConfigsFromLibs.filter(
    (asset) => !existingAssetsObjects.some(({ input }) => input.includes(asset.libraryRoot))
  );

  const assetsToUpdate = assetConfigsFromLibs.filter((createdAsset) => {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const { libraryRoot, ...createdAssetConfigWithoutRoot } = createdAsset;

    return existingAssetsObjects.some(
      (existingAsset) =>
        existingAsset.input.includes(createdAsset.libraryRoot) &&
        JSON.stringify(createdAssetConfigWithoutRoot) !== JSON.stringify(existingAsset)
    );
  });

  return {
    assetsToAdd,
    assetsToUpdate
  };
}

function createAssetConfigsFromLibs(
  tree: Tree,
  libraries: LibraryConfiguration[]
): AssetPatternWithRoot[] {
  const result = libraries.reduce((acc: AssetPatternWithRoot[], lib: LibraryConfiguration) => {
    const libraryRoot = getLibraryRoot(tree, lib.package);
    const libraryJsonPath = joinPathFragments(libraryRoot, 'library.json');

    if (!tree.exists(libraryJsonPath)) {
      return acc;
    }

    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const libraryJsonContent = tree.read(libraryJsonPath, 'utf-8')!;
    const libraryJson = JSON.parse(libraryJsonContent);
    if (!libraryJson.assets) {
      return acc;
    }

    acc.push({
      glob: '**/*',
      input: `${libraryRoot}/${libraryJson.assets}`,
      output: `/assets/`,
      libraryRoot: libraryRoot
    });

    return acc;
  }, []);

  return result;
}

function getLibraryRoot(tree: Tree, packageName: string) {
  try {
    const internalLibraryRoot = readProjectConfiguration(tree, packageName).root;
    return internalLibraryRoot;
  } catch {
    const externalLibraryRoot = joinPathFragments('node_modules', packageName);
    return externalLibraryRoot;
  }
}

results matching ""

    No results matching ""