2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/**
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * @license
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * Copyright Google LLC All Rights Reserved.
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Use of this source code is governed by an MIT-style license that can be
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * found in the LICENSE file at https://angular.io/license
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import {existsSync, readFileSync, writeFileSync} from 'fs';
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import {sync as globSync} from 'glob';
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-24 15:43:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import {isAbsolute, relative, resolve} from 'path';
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import * as ts from 'typescript';
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import * as yargs from 'yargs';
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-10-01 16:06:56 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import {error, green, info, red, yellow} from '../utils/console';
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import {Analyzer, ReferenceChain} from './analyzer';
							 | 
						
					
						
							
								
									
										
										
										
											2020-10-01 16:06:56 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import {CircularDependenciesTestConfig, loadTestConfig} from './config';
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import {convertPathToForwardSlash} from './file_system';
							 | 
						
					
						
							
								
									
										
										
										
											2020-10-01 16:06:56 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import {compareGoldens, convertReferenceChainToGolden, Golden} from './golden';
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-26 10:45:09 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export function tsCircularDependenciesBuilder(localYargs: yargs.Argv) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return localYargs.help()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      .strict()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      .demandCommand()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      .option(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          'config',
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          {type: 'string', demandOption: true, description: 'Path to the configuration file.'})
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      .option('warnings', {type: 'boolean', description: 'Prints all warnings.'})
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      .command(
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-14 12:20:55 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								          'check', 'Checks if the circular dependencies have changed.', args => args,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          argv => {
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-26 10:45:09 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            const {config: configArg, warnings} = argv;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            const configPath = isAbsolute(configArg) ? configArg : resolve(configArg);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            const config = loadTestConfig(configPath);
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-14 12:20:55 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            process.exit(main(false, config, !!warnings));
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-26 10:45:09 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								          })
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-14 12:20:55 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      .command('approve', 'Approves the current circular dependencies.', args => args, argv => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const {config: configArg, warnings} = argv;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const configPath = isAbsolute(configArg) ? configArg : resolve(configArg);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const config = loadTestConfig(configPath);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        process.exit(main(true, config, !!warnings));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      });
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/**
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Runs the ts-circular-dependencies tool.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * @param approve Whether the detected circular dependencies should be approved.
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-24 15:43:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * @param config Configuration for the current circular dependencies test.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * @param printWarnings Whether warnings should be printed out.
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * @returns Status code.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export function main(
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-24 15:43:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    approve: boolean, config: CircularDependenciesTestConfig, printWarnings: boolean): number {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const {baseDir, goldenFile, glob, resolveModule, approveCommand} = config;
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const analyzer = new Analyzer(resolveModule);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const cycles: ReferenceChain[] = [];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const checkedNodes = new WeakSet<ts.SourceFile>();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  globSync(glob, {absolute: true}).forEach(filePath => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const sourceFile = analyzer.getSourceFile(filePath);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    cycles.push(...analyzer.findCycles(sourceFile, checkedNodes));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  });
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const actual = convertReferenceChainToGolden(cycles, baseDir);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  info(green(`   Current number of cycles: ${yellow(cycles.length.toString())}`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (approve) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    writeFileSync(goldenFile, JSON.stringify(actual, null, 2));
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    info(green('✅  Updated golden file.'));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  } else if (!existsSync(goldenFile)) {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    error(red(`❌  Could not find golden file: ${goldenFile}`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-24 15:43:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  const warningsCount = analyzer.unresolvedFiles.size + analyzer.unresolvedModules.size;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // By default, warnings for unresolved files or modules are not printed. This is because
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // it's common that third-party modules are not resolved/visited. Also generated files
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // from the View Engine compiler (i.e. factories, summaries) cannot be resolved.
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-24 15:43:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  if (printWarnings && warningsCount !== 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    info(yellow('⚠  The following imports could not be resolved:'));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    Array.from(analyzer.unresolvedModules).sort().forEach(specifier => info(`  • ${specifier}`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    analyzer.unresolvedFiles.forEach((value, key) => {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      info(`  • ${getRelativePath(baseDir, key)}`);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      value.sort().forEach(specifier => info(`      ${specifier}`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    });
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-24 15:43:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  } else {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    info(yellow(`⚠  ${warningsCount} imports could not be resolved.`));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    info(yellow(`   Please rerun with "--warnings" to inspect unresolved imports.`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const expected: Golden = JSON.parse(readFileSync(goldenFile, 'utf8'));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const {fixedCircularDeps, newCircularDeps} = compareGoldens(actual, expected);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const isMatching = fixedCircularDeps.length === 0 && newCircularDeps.length === 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (isMatching) {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    info(green('✅  Golden matches current circular dependencies.'));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  error(red('❌  Golden does not match current circular dependencies.'));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (newCircularDeps.length !== 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    error(yellow(`   New circular dependencies which are not allowed:`));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    newCircularDeps.forEach(c => error(`     • ${convertReferenceChainToString(c)}`));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    error();
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (fixedCircularDeps.length !== 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    error(yellow(`   Fixed circular dependencies that need to be removed from the golden:`));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    fixedCircularDeps.forEach(c => error(`     • ${convertReferenceChainToString(c)}`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-10 18:15:32 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    info(yellow(`\n   Total: ${newCircularDeps.length} new cycle(s), ${
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        fixedCircularDeps.length} fixed cycle(s). \n`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-24 15:43:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (approveCommand) {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      info(yellow(`   Please approve the new golden with: ${approveCommand}`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:08:24 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 14:52:19 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      info(yellow(
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:08:24 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								          `   Please update the golden. The following command can be ` +
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-24 15:43:54 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								          `run: yarn ts-circular-deps approve ${getRelativePath(process.cwd(), goldenFile)}.`));
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:08:24 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-24 12:03:15 +01:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/** Gets the specified path relative to the base directory. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								function getRelativePath(baseDir: string, path: string) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return convertPathToForwardSlash(relative(baseDir, path));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/** Converts the given reference chain to its string representation. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								function convertReferenceChainToString(chain: ReferenceChain<string>) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return chain.join(' → ');
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 |