Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ts_project cannot compile a ts file that imports a generated json file #2843

Closed
alexeagle opened this issue Aug 3, 2021 · 10 comments
Closed
Labels
Can Close? We will close this in 30 days if there is no further activity

Comments

@alexeagle
Copy link
Collaborator

alexeagle commented Aug 3, 2021

The TypeScript compiler treats .json files as sources that must be within the rootDir. Unlike resolution of .d.ts files for typings, we can't simply pre-process the generated .json files as a separate project.

Repro:

a.ts:

import {name} from './gen.json'

BUILD:

load("@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel-skylib:rules/write_file.bzl", "write_file")
load("//packages/typescript:index.bzl", "ts_project")

write_file(
    name = "gen_json",
    out = "subdir/gen.json",
    content = ["""{ "name": "gen-json" }"""],
)

ts_project(
    name = "compile",
    srcs = ["a.ts", "gen.json"],
    tsconfig = "tsconfig.json",
)

tsconfig.json:

{
    "compilerOptions": {
        "resolveJsonModule": true,
        "rootDirs": [
            ".",
            "../../../../../bazel-out/darwin-fastbuild/bin/packages/typescript/test/ts_project/json",
            "../../../../../bazel-out/k8-fastbuild/bin/packages/typescript/test/ts_project/json",
        ]
    }
}

Error:

packages/typescript/test/ts_project/json/a.ts(1,20): error TS6059: 
File '[execroot]/build_bazel_rules_nodejs/bazel-out/darwin-fastbuild/bin/packages/typescript/test/ts_project/json/gen.json'
 is not under 'rootDir' '[execroot]/build_bazel_rules_nodejs/packages/typescript/test/ts_project/json'.
 'rootDir' is expected to contain all source files.

However if the json file were represented as typings, then it would work. That is, when performing type-checking we would want a generated .d.ts file to show the type-shape of the json file. This would presumably be the output of some other rule that turns json schema into TypeScript typings, like the compiler does internally, but exposed as a separate "project".

With the same a.ts and tsconfig.json as above, this now works:

write_file(
    name = "gen_json",
    out = "gen.json",
    content = ["""{ "name": "gen-json" }"""],
)
write_file(
    name = "gen_json_typing",
    out = "gen.json.d.ts",
    content = ["export declare const name = 'gen-json'"],
)
ts_project(
    name = "compile",
    srcs = ["a.ts", "gen.json", "gen.json.d.ts"],
    tsconfig = "tsconfig.json",
)

However it's not really feasible for users to have to generate typings for their json manually, they want to do the simple thing that TypeScript normally supports if the .json file were actually located with the sources.

It feels like the JSON import feature added to TypeScript is just missing the pathmapping resolution logic that exists for .d.ts files, and so we ought to be able to file a bug upstream on the TypeScript project.

@alexeagle
Copy link
Collaborator Author

microsoft/TypeScript#24744 kinda suggests "json always treated as a module" which is similar. In fact the JSON sources are always written to the output tree, which is why TS needs them to conform to the rootDir/outDir scheme that .ts inputs would. What we really want here is to say "you can use this json file to typecheck against, but there's no need to copy it to the output folder since it's already there".

@alexeagle
Copy link
Collaborator Author

microsoft/TypeScript#36066 seems to explicitly break what we wanted here, which is a way to get the typeshape for the json file without having to treat it as an emittable source.

@gregmagolan
Copy link
Collaborator

I've successfully worked around this issue by using https://www.npmjs.com/package/json-to-dts to generate .d.ts files which can be passed to a ts_project via a js_library (to pick up DeclarationInfo provider). With this approach the .d.ts files can be passed to the ts_project rule instead of the generated json and ts_project doesn't complain about the root directory violation.

@loudmouth
Copy link

@gregmagolan this is awesome.

Just curious, are use using an npm_package_bin rule to invoke json-to-dts? have any example code you're able and willing to share?

@loudmouth
Copy link

loudmouth commented Nov 3, 2021

hey @gregmagolan just thought i'd bump up my last message and see if you had anything shareable for this topic. I've attempted invoking json-to-dts via npm_package_bin but struggling...

was able to use npm_package_bin to generate declarations. now for the next part...

@loudmouth
Copy link

loudmouth commented Nov 4, 2021

According to my understanding of the comment left above, I have used used json-dts-generator as an npm_package_bin. While I was able to successfully "build" a js_library that uses the generated type declarations as well as my static data (i.e. JSON file), trying to resolve JavaScript require/imports inside a ts_project in a separate path in the workspace results in the compiler being unable to find the file. This is despite having rootDirs configured properly in tsconfig.json and having link_workspace_root = True in the ts_project rule.

Note: i'm also using the links attribute of yarn_install to link the js_library to the ts_project but it doesn't seem to make a data-lib available as an import

load("@npm//json-dts-generator:index.bzl", "json_dts_generator")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "copy_to_bin")

package(default_visibility = ["//visibility:public"])

filegroup(
    name = "data",
    srcs = [
        "data.json",
    ],
)

copy_to_bin(
    name = "srcs",
    srcs = ["data.json"]
)

json_dts_generator(
    name = "data_declarations",
    outs = [
        "_common.d.ts",
        "data.d.ts",
    ],
    data = [":srcs"],
    args = ["$(RULEDIR) $(RULEDIR)"],
)

js_library(
    name = "data_js",
    package_name = "data-lib",
    package_path = "path/to/lib",
    srcs = [
        ":data.json", 
        "_common.d.ts",
        "data.d.ts",
    ],
    deps = [
        ":data_declarations",
    ],
)

@gregmagolan
Copy link
Collaborator

I put up a minimal example of using the json-to-dts package I forked from json-dts-generator. https://github.com/gregmagolan/json-to-dts-example/blob/main/src/BUILD.bazel. Hope that helps.

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had any activity for 6 months. It will be closed if no further activity occurs in 30 days. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs!

@github-actions github-actions bot added the Can Close? We will close this in 30 days if there is no further activity label May 11, 2022
@github-actions
Copy link

This issue was automatically closed because it went 30 days without any activity since it was labeled "Can Close?"

@alexeagle
Copy link
Collaborator Author

Note, this is fixed in https://github.com/aspect-build/rules_ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Can Close? We will close this in 30 days if there is no further activity
Projects
None yet
Development

No branches or pull requests

3 participants