1# -*- bazel-starlark -*- 2load("@builtin//encoding.star", "json") 3load("@builtin//path.star", "path") 4load("@builtin//struct.star", "module") 5 6def _load(ctx, tsconfig_path, loaded): 7 if tsconfig_path in loaded: 8 return loaded[tsconfig_path] 9 tsconfig = json.decode(str(ctx.fs.read(tsconfig_path))) 10 loaded[tsconfig_path] = tsconfig 11 return tsconfig 12 13def _paths(ctx, tsconfig_path, tsconfig, loaded): 14 paths = [tsconfig_path] 15 tsconfig_dir = path.dir(tsconfig_path) 16 if "extends" in tsconfig and tsconfig["extends"]: 17 base = path.join(tsconfig_dir, tsconfig["extends"]) 18 paths.append(base) 19 parent = _load(ctx, base, loaded) 20 if "files" in parent and not tsconfig["files"]: 21 tsconfig["files"] = parent["files"] 22 if "files" in tsconfig: 23 for file in tsconfig["files"]: 24 paths.append(path.join(tsconfig_dir, file)) 25 if file.endswith(".js"): 26 # Add if d.ts version of the file exists. 27 file_dts = path.join(tsconfig_dir, file[:-2] + "d.ts") 28 if ctx.fs.exists(file_dts): 29 paths.append(file_dts) 30 return paths 31 32def _scan_inputs(ctx, tsconfig_path, tsconfig, loaded, scanned): 33 if tsconfig_path in scanned: 34 return scanned[tsconfig_path] 35 inputs = {} 36 for fname in _paths(ctx, tsconfig_path, tsconfig, loaded): 37 if fname not in inputs: 38 inputs[fname] = True 39 if "references" in tsconfig: 40 for ref in tsconfig["references"]: 41 refname = path.join(path.dir(tsconfig_path), ref["path"]) 42 if refname not in inputs: 43 inputs[refname] = True 44 reftc = _load(ctx, refname, loaded) 45 for fname in _scan_inputs(ctx, refname, reftc, loaded, scanned): 46 if fname not in inputs: 47 inputs[fname] = True 48 scanned[tsconfig_path] = inputs.keys() 49 return scanned[tsconfig_path] 50 51def _scandeps(ctx, tsconfig_path, tsconfig): 52 loaded = {tsconfig_path: tsconfig} 53 scanned = {} 54 inputs = _scan_inputs(ctx, tsconfig_path, tsconfig, loaded, scanned) 55 return inputs 56 57tsc = module( 58 "tsc", 59 scandeps = _scandeps, 60) 61