Skip to content

Commit

Permalink
refactor(compiler): add a Result union type for polymorphic returns
Browse files Browse the repository at this point in the history
  • Loading branch information
khanhduy1407 committed Dec 1, 2023
1 parent 092d870 commit 4538cbf
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 36 deletions.
2 changes: 2 additions & 0 deletions scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { mockDoc } from './bundles/mock-doc';
import { screenshot } from './bundles/screenshot';
import { sysNode, sysNodeExternalBundles } from './bundles/sys-node';
import { testing } from './bundles/testing';
import { utils } from './bundles/utils';
import { createLicense } from './license';
import { release } from './release';
import { validateBuild } from './test/validate-build';
Expand Down Expand Up @@ -66,6 +67,7 @@ export async function createBuild(opts: BuildOptions): Promise<readonly RollupOp
screenshot(opts),
testing(opts),
sysNode(opts),
utils(opts),
]);

return bundles.flat();
Expand Down
6 changes: 5 additions & 1 deletion scripts/bundles/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ async function copyRindoInternalDts(opts: BuildOptions, outputInternalDir: strin
// @rindo/core/internal/rindo-private.d.ts
const privateDtsSrcPath = join(declarationsInputDir, 'rindo-private.d.ts');
const privateDtsDestPath = join(outputInternalDir, 'rindo-private.d.ts');
const privateDts = cleanDts(await fs.readFile(privateDtsSrcPath, 'utf8'));
let privateDts = cleanDts(await fs.readFile(privateDtsSrcPath, 'utf8'));

// the private `.d.ts` imports the `Result` type from the `@utils` module, so
// we need to rewrite the path so it imports from the right relative path
privateDts = privateDts.replace('@utils', './utils');
await fs.writeFile(privateDtsDestPath, privateDts);

// @rindo/core/internal/rindo-public.compiler.d.ts
Expand Down
44 changes: 44 additions & 0 deletions scripts/bundles/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import fs from 'fs-extra';
import { join } from 'path';

import { BuildOptions } from '../utils/options';

/**
* A nearly-empty bundle which is responsible for copying the typedef files for
* the `src/utils/` module to the right location (`internal/util.d.ts`)
*
* @param opts options set for the Rollup build
* @returns an (empty) array of Rollup option objects
*/
export async function utils(opts: BuildOptions) {
await copyUtilsDtsFiles(opts);
// dummy return to agree with type of other bundles
return [];
}

/**
* Copy `.d.ts` files built from `src/utils` to `internal/utils` so that types
* exported from utility modules can be referenced by other typedefs (in
* particular by our declarations).
*
* Some modules within `@utils` incorporate external types which aren't bundled
* so we selectively copy only `.d.ts` files which are 1) standalone and 2) export
* a type that other modules in the codebase (in, for instance, `src/compiler/`
* or `src/cli/`) depend on.
*
* @param opts options for the rollup build
*/
const copyUtilsDtsFiles = async (opts: BuildOptions) => {
const outputDirPath = join(opts.output.internalDir, 'utils');
await fs.ensureDir(outputDirPath);

// copy the `.d.ts` file corresponding to `src/utils/result.ts`
const resultDtsFilePath = join(opts.buildDir, 'utils', 'result.d.ts');
const resultDtsOutputFilePath = join(opts.output.internalDir, 'utils', 'result.d.ts');
await fs.copyFile(resultDtsFilePath, resultDtsOutputFilePath);

const utilsIndexDtsPath = join(opts.output.internalDir, 'utils', 'index.d.ts');
// here we write a simple module that re-exports `./result` so that imports
// elsewhere like `import { result } from '@utils'` will resolve correctly
await fs.writeFile(utilsIndexDtsPath, `export * as result from "./result"`);
};
13 changes: 6 additions & 7 deletions src/cli/find-config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { buildError, isString, normalizePath } from '@utils';
import { buildError, isString, normalizePath, result } from '@utils';

import type { CompilerSystem, Diagnostic } from '../declarations';

Expand All @@ -17,15 +17,14 @@ export type FindConfigOptions = {
export type FindConfigResults = {
configPath: string;
rootDir: string;
diagnostics: Diagnostic[];
};

/**
* Attempt to find a Rindo configuration file on the file system
* @param opts the options needed to find the configuration file
* @returns the results of attempting to find a configuration file on disk
*/
export const findConfig = async (opts: FindConfigOptions): Promise<FindConfigResults> => {
export const findConfig = async (opts: FindConfigOptions): Promise<result.Result<FindConfigResults, Diagnostic[]>> => {
const sys = opts.sys;
const cwd = sys.getCurrentDirectory();
const rootDir = normalizePath(cwd);
Expand All @@ -49,16 +48,16 @@ export const findConfig = async (opts: FindConfigOptions): Promise<FindConfigRes
const results: FindConfigResults = {
configPath,
rootDir: normalizePath(cwd),
diagnostics: [],
};

const stat = await sys.stat(configPath);
if (stat.error) {
const diagnostic = buildError(results.diagnostics);
const diagnostics: Diagnostic[] = [];
const diagnostic = buildError(diagnostics);
diagnostic.absFilePath = configPath;
diagnostic.header = `Invalid config path`;
diagnostic.messageText = `Config path "${configPath}" not found`;
return results;
return result.err(diagnostics);
}

if (stat.isFile) {
Expand All @@ -77,5 +76,5 @@ export const findConfig = async (opts: FindConfigOptions): Promise<FindConfigRes
}
}

return results;
return result.ok(results);
};
9 changes: 5 additions & 4 deletions src/cli/run.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { hasError, isFunction, shouldIgnoreError } from '@utils';
import { hasError, isFunction, result, shouldIgnoreError } from '@utils';

import type * as d from '../declarations';
import { ValidatedConfig } from '../declarations';
Expand Down Expand Up @@ -46,8 +46,8 @@ export const run = async (init: d.CliInitOptions) => {
startupLog(logger, task);

const findConfigResults = await findConfig({ sys, configPath: flags.config });
if (hasError(findConfigResults.diagnostics)) {
logger.printDiagnostics(findConfigResults.diagnostics);
if (findConfigResults.isErr) {
logger.printDiagnostics(findConfigResults.value);
return sys.exit(1);
}

Expand All @@ -67,11 +67,12 @@ export const run = async (init: d.CliInitOptions) => {
return;
}

const foundConfig = result.unwrap(findConfigResults);
const validated = await coreCompiler.loadConfig({
config: {
flags,
},
configPath: findConfigResults.configPath,
configPath: foundConfig.configPath,
logger,
sys,
});
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/build/build-ctx.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { hasError, hasWarning } from '@utils';
import { hasError, hasWarning, result } from '@utils';

import type * as d from '../../declarations';

Expand All @@ -18,7 +18,7 @@ export class BuildContext implements d.BuildCtx {
componentGraph = new Map<string, string[]>();
config: d.Config;
data: any = {};
buildStats?: d.CompilerBuildStats = undefined;
buildStats?: result.Result<d.CompilerBuildStats, { diagnostics: d.Diagnostic[] }> = undefined;
esmBrowserComponentBundle: d.BundleModule[];
esmComponentBundle: d.BundleModule[];
es5ComponentBundle: d.BundleModule[];
Expand Down
39 changes: 18 additions & 21 deletions src/compiler/build/build-stats.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { byteSize, isOutputTargetStats, sortBy } from '@utils';
import { byteSize, isOutputTargetStats, result, sortBy } from '@utils';

import type * as d from '../../declarations';

Expand All @@ -11,17 +11,15 @@ import type * as d from '../../declarations';
export function generateBuildStats(
config: d.Config,
buildCtx: d.BuildCtx
): d.CompilerBuildStats | { diagnostics: d.Diagnostic[] } {
): result.Result<d.CompilerBuildStats, { diagnostics: d.Diagnostic[] }> {
// TODO(RINDO-461): Investigate making this return only a single type
const buildResults = buildCtx.buildResults;

let jsonData: d.CompilerBuildStats | { diagnostics: d.Diagnostic[] };

try {
if (buildResults.hasError) {
jsonData = {
return result.err({
diagnostics: buildResults.diagnostics,
};
});
} else {
const stats: d.CompilerBuildStats = {
timestamp: buildResults.timestamp,
Expand Down Expand Up @@ -58,8 +56,7 @@ export function generateBuildStats(
rollupResults: buildCtx.rollupResults,
collections: getCollections(config, buildCtx),
};

jsonData = stats;
return result.ok(stats);
}
} catch (e: unknown) {
const diagnostic: d.Diagnostic = {
Expand All @@ -68,12 +65,10 @@ export function generateBuildStats(
messageText: `Generate Build Stats Error: ` + e,
type: `build`,
};
jsonData = {
return result.err({
diagnostics: [diagnostic],
};
});
}

return jsonData;
}

/**
Expand All @@ -84,19 +79,21 @@ export function generateBuildStats(
*/
export async function writeBuildStats(
config: d.Config,
data: d.CompilerBuildStats | { diagnostics: d.Diagnostic[] }
data: result.Result<d.CompilerBuildStats, { diagnostics: d.Diagnostic[] }>
): Promise<void> {
const statsTargets = config.outputTargets.filter(isOutputTargetStats);

await Promise.all(
statsTargets.map(async (outputTarget) => {
const result = await config.sys.writeFile(outputTarget.file, JSON.stringify(data, null, 2));
await result.map(data, async (compilerBuildStats) => {
await Promise.all(
statsTargets.map(async (outputTarget) => {
const result = await config.sys.writeFile(outputTarget.file, JSON.stringify(compilerBuildStats, null, 2));

if (result.error) {
config.logger.warn([`Stats failed to write file to ${outputTarget.file}`]);
}
})
);
if (result.error) {
config.logger.warn([`Stats failed to write file to ${outputTarget.file}`]);
}
})
);
});
}

function sanitizeBundlesForStats(bundleArray: ReadonlyArray<d.BundleModule>): ReadonlyArray<d.CompilerBuildStatBundle> {
Expand Down
4 changes: 3 additions & 1 deletion src/declarations/rindo-private.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { result } from '@utils';

import type { InMemoryFileSystem } from '../compiler/sys/in-memory-fs';
import type {
BuildEvents,
Expand Down Expand Up @@ -207,7 +209,7 @@ export interface UpdatedLazyBuildCtx {
export interface BuildCtx {
buildId: number;
buildResults: CompilerBuildResults;
buildStats?: CompilerBuildStats | { diagnostics: Diagnostic[] };
buildStats?: result.Result<CompilerBuildStats, { diagnostics: Diagnostic[] }>;
buildMessages: string[];
bundleBuildCount: number;
collections: Collection[];
Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './message-utils';
export * from './output-target';
export * from './path';
export * from './query-nonce-meta-tag-content';
export * as result from './result';
export * from './sourcemaps';
export * from './url-paths';
export * from './util';
Expand Down
Loading

0 comments on commit 4538cbf

Please sign in to comment.