import * as fs from "fs" ; import { PackageDetails } from "./packageJson" ; import { generateTypeDataForProject , toTypeString , TypeData } from "./typeData" ; export function generateTests ( packageDetails ) { const currentProjectData = generateTypeDataForProject ( packageDetails . packageDir , undefined ) ; let indexPath = "../.." ; for ( const oldVersion of packageDetails . oldVersions ) { const testString = [ `/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
/*
 * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
 * Generated by fluid-type-validator in @fluidframework/build-tools.
 */
import * as old from "${ oldVersion }";
import * as current from "${ indexPath }/index";
` ] ; const oldProjectData = generateTypeDataForProject ( packageDetails . packageDir , oldVersion ) ; const currentTypeMap = new Map < string , TypeData > ( currentProjectData . typeData . map ( ( v ) => [ getFullTypeName ( v ) , v ] ) ) ; for ( const oldTypeData of oldProjectData . typeData ) { const oldType = { prefix : "old" , ... oldTypeData , } ; const currentTypeData = currentTypeMap . get ( getFullTypeName ( oldTypeData ) ) ; const currentType = currentTypeData === undefined ? { prefix : "current" , ... oldTypeData , kind : `Removed${ oldTypeData . kind }` , } : { prefix : "current" , ... currentTypeData , } ; const brokenData = currentProjectData . packageDetails . broken ?. [ oldProjectData . packageDetails . version ] ?. [ getFullTypeName ( currentType ) ] ; testString . push ( `/*` ) ; testString . push ( `* Validate forward compat by using old type in place of current type` ) ; testString . push ( `* If breaking change required, add in package.json under typeValidation.broken.${ oldProjectData . packageDetails . version }:` ) ; testString . push ( `* "${ getFullTypeName ( currentType ) }": {"forwardCompat": false}` ) ; testString . push ( "*/" ) ; testString . push ( ... buildTestCase ( oldType , currentType , brokenData ?. forwardCompat ?? true ) ) ; testString . push ( "" ) ; testString . push ( `/*` ) ; testString . push ( `* Validate back compat by using current type in place of old type` ) ; testString . push ( `* If breaking change required, add in package.json under typeValidation.broken.${ oldProjectData . packageDetails . version }:` ) ; testString . push ( `* "${ getFullTypeName ( currentType ) }": {"backCompat": false}` ) ; testString . push ( "*/" ) ; testString . push ( ... buildTestCase ( currentType , oldType , brokenData ?. backCompat ?? true ) ) ; testString . push ( "" ) ; } const testPath = `${ packageDetails . packageDir }/src/test/types` ; if ( ! fs . existsSync ( testPath ) ) { fs . mkdirSync ( testPath ) ; } fs . writeFileSync ( `${ testPath }/validate${ oldProjectData . packageDetails . version }.ts` , testString . join ( "\n" ) ) ; } } interface TestCaseTypeData extends TypeData { prefix : "old" | "current" ; } function buildTestCase ( getAsType , useType , isCompatible ) { const getSig = `get_${ getAsType . prefix }_${ getFullTypeName ( getAsType ) . replace ( "." , "_" ) }` ; const useSig = `use_${ useType . prefix }_${ getFullTypeName ( useType ) . replace ( "." , "_" ) }` ; const testString = [ ] ; testString . push ( `declare function ${ getSig }():\n    ${ toTypeString ( getAsType . prefix , getAsType ) };` ) ; testString . push ( `declare function ${ useSig }(\n    use: ${ toTypeString ( useType . prefix , useType ) });` ) ; testString . push ( `${ useSig }(` ) ; if ( ! isCompatible ) { testString . push ( `    // @ts-expect-error compatibility expected to be broken` ) ; } testString . push ( `    ${ getSig }());` ) ; return testString ; } function getFullTypeName ( typeData ) { return `${ typeData . kind }_${ typeData . name }` ; }