f862536ec4
Currently on Windows, it's not possible to approve goldens in `ts-api-guardian`. This is because paths are resolved relatively to the working directory. In Windows, golden files are resolved to the actual workspace directory. The current logic tries to compute a relative path to the runfile from the working directory. This causes the file paths to have a lot of parent directory path segments. Eventually, when joined with the build workspace directory, the paths end up being incorrect. e.g. ``` fileName = ../../../../../../projects/angular/golden/<..>/common.d.ts` outFile = BUILD_WORKSPACE_DIR + fileName; ``` To fix this, we no longer deal with confusing relative paths, but instead always use absolute file system paths. Additionally, this fixes that new goldens are generated at the wrong location on all platforms. PR Close #36096
94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* 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 {createPatch} from 'diff';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import {SerializationOptions, publicApi} from './serializer';
|
|
|
|
export {SerializationOptions, publicApi} from './serializer';
|
|
|
|
export function generateGoldenFile(
|
|
entrypoint: string, outFile: string, options: SerializationOptions = {}): void {
|
|
const output = publicApi(entrypoint, options);
|
|
|
|
ensureDirectory(path.dirname(outFile));
|
|
fs.writeFileSync(outFile, output);
|
|
}
|
|
|
|
export function verifyAgainstGoldenFile(
|
|
entrypoint: string, goldenFile: string, options: SerializationOptions = {}): string {
|
|
const actual = publicApi(entrypoint, options);
|
|
const expected = fs.existsSync(goldenFile) ? fs.readFileSync(goldenFile).toString() : '';
|
|
|
|
if (actual === expected) {
|
|
return '';
|
|
} else {
|
|
const displayFileName = path.relative(process.cwd(), goldenFile);
|
|
const patch = createPatch(displayFileName, expected, actual, 'Golden file', 'Generated API');
|
|
|
|
// Remove the header of the patch
|
|
const start = patch.indexOf('\n', patch.indexOf('\n') + 1) + 1;
|
|
|
|
return patch.substring(start);
|
|
}
|
|
}
|
|
|
|
function ensureDirectory(dir: string) {
|
|
if (!fs.existsSync(dir)) {
|
|
ensureDirectory(path.dirname(dir));
|
|
fs.mkdirSync(dir);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine if the provided path is a directory.
|
|
*/
|
|
function isDirectory(dirPath: string) {
|
|
try {
|
|
return fs.lstatSync(dirPath).isDirectory();
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets an array of paths to the typings files for each of the recursively discovered
|
|
* package.json
|
|
* files from the directory provided.
|
|
*/
|
|
export function discoverAllEntrypoints(dirPath: string) {
|
|
// Determine all of the package.json files
|
|
const packageJsons: string[] = [];
|
|
const entryPoints: string[] = [];
|
|
const findPackageJsonsInDir = (nextPath: string) => {
|
|
for (const file of fs.readdirSync(nextPath)) {
|
|
const fullPath = path.join(nextPath, file);
|
|
if (isDirectory(fullPath)) {
|
|
findPackageJsonsInDir(fullPath);
|
|
} else {
|
|
if (file === 'package.json') {
|
|
packageJsons.push(fullPath);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
findPackageJsonsInDir(dirPath);
|
|
|
|
// Get all typings file locations from package.json files
|
|
for (const packageJson of packageJsons) {
|
|
const packageJsonObj = JSON.parse(fs.readFileSync(packageJson, {encoding: 'utf8'}));
|
|
const typings = packageJsonObj.typings;
|
|
if (typings) {
|
|
entryPoints.push(path.join(path.dirname(packageJson), typings));
|
|
}
|
|
}
|
|
|
|
return entryPoints;
|
|
}
|