Skip to content

Commit

Permalink
Fixed inference when using npm packages
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-chambers committed Nov 23, 2023
1 parent 40b4189 commit e4c86ca
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/node_modules
node_modules/
/target
.vscode/
vendor/
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ Limitations:
* Functions can be executed via both the `/query` and `/mutation` endpoints
* Conflicting type names in dependencies will be namespaced with their relative path
* Generic type parameters will be treated as scalars when referenced
* Deno's `npm:` specifier doesn't currently work with the vendor command

Please [file an issue](https://github.com/hasura/ndc-typescript-deno/issues/new) for any problems you encounter during usage of this connector.

Expand Down Expand Up @@ -343,7 +342,7 @@ In order to perform local development on this codebase:

* Check out the repository: `git clone https://github.com/hasura/ndc-typescript-deno.git`
* This assumes that you will be testing against function in `./functions`
* Vendor the dependencies with `cd ./function && deno vendor -f index.ts`
* Vendor the dependencies with `cd ./function && deno vendor --node-modules-dir -f index.ts`
* Serve your functions with `deno run -A --watch --check ./src/mod.ts serve --configuration <(echo '{"functions": "./functions/index.ts", "vendor": "./functions/vendor", "schemaMode": "INFER"}')`
* The connector should now be running on localhost:8100 and respond to any changes to the your functions and the connector source
* Use the `hasura3` tunnel commands to reference this connector from a Hasura Cloud project
Expand Down
2 changes: 1 addition & 1 deletion src/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ if [ -d vendor ]
then
echo "found existing vendor results"
else
deno vendor -f index.ts
deno vendor --node-modules-dir -f index.ts
deno vendor -f /app/mod.ts
fi

Expand Down
30 changes: 24 additions & 6 deletions src/infer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Dependencies are required to be vendored before invocation.
*/

import ts, { FunctionDeclaration } from "npm:[email protected]";
import ts, { FunctionDeclaration, StringLiteralLike } from "npm:[email protected]";
import { resolve, dirname } from "https://deno.land/[email protected]/path/mod.ts";
import { existsSync } from "https://deno.land/[email protected]/fs/mod.ts";
import * as sdk from 'npm:@hasura/[email protected]';
Expand Down Expand Up @@ -187,7 +187,7 @@ function pre_vendor(vendorPath: string, filename: string) {
// Exampe taken from:
// https://docs.deno.com/runtime/tutorials/subprocess
const deno_exec_path = Deno.execPath();
const vendor_args = [ "vendor", "--output", vendorPath, "--force", filename ];
const vendor_args = [ "vendor", "--node-modules-dir", "--output", vendorPath, "--force", filename ];

console.error(`Vendoring dependencies: ${[deno_exec_path, ...vendor_args].join(" ")}`);

Expand Down Expand Up @@ -370,9 +370,9 @@ export function programInfoException(filename_arg?: string, vendor_arg?: string,
}
`);

const program = ts.createProgram([filename], {
const compilerOptions: ts.CompilerOptions = {
// This should match the version targeted in the deno version that is being used.
target: ts.ScriptTarget.ES2022,
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS,
noImplicitAny: true,
// NOTE: We just declare Deno globally as any in order to allow users to omit it's declaration in their function files
Expand All @@ -383,7 +383,26 @@ export function programInfoException(filename_arg?: string, vendor_arg?: string,
noEmit: true,
baseUrl: '.',
paths: pathsMap
});
};

const host = ts.createCompilerHost(compilerOptions);
host.resolveModuleNameLiterals = (moduleLiterals: StringLiteralLike[], containingFile: string): ts.ResolvedModuleWithFailedLookupLocations[] => {
return moduleLiterals.map(moduleName => {
let moduleNameToResolve = moduleName.text;
// If this looks like a Deno "npm:pkgName[@version][/path]" module import, extract the node module
// name and resolve that instead. So long as we've done a deno vendor with --node-modules-dir
// then we'll have a node_modules directory that the standard TypeScript module resolution
// process can locate the npm package in by its name
const npmDepMatch = /^npm:(?<pkgName>(?:@.+?\/)?[^/\n]+?)(?:@.+)?(?:\/.+)?$/.exec(moduleName.text);
if (npmDepMatch) {
moduleNameToResolve = npmDepMatch.groups?.pkgName!;
}

return ts.resolveModuleName(moduleNameToResolve, containingFile, compilerOptions, { fileExists: host.fileExists, readFile: host.readFile });
})
}

const program = ts.createProgram([filename], compilerOptions, host);

Deno.removeSync(deno_d_ts);

Expand Down Expand Up @@ -535,4 +554,3 @@ export function programInfoException(filename_arg?: string, vendor_arg?: string,

return result;
}

26 changes: 24 additions & 2 deletions src/test/external_dependencies_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,44 @@ import * as infer from '../infer.ts';
// Skipped due to NPM dependency resolution not currently being supported.
Deno.test({
name: "Inference",
ignore: true,
fn() {
const program_path = path.fromFileUrl(import.meta.resolve('./data/external_dependencies.ts'));
const vendor_path = path.fromFileUrl(import.meta.resolve('./vendor'));
const program_results = infer.programInfo(program_path, vendor_path, false);
const program_results = infer.programInfo(program_path, vendor_path, true);

test.assertEquals(program_results, {
positions: {
test_deps: [
"s"
]
},
schema: {
scalar_types: {
String: {
aggregate_functions: {},
comparison_operators: {},
update_operators: {},
},
},
object_types: {},
collections: [],
functions: [],
procedures: [
{
name: "test_deps",
arguments: {
s: {
type: {
name: "String",
type: "named",
},
},
},
result_type: {
name: "String",
type: "named",
},
},
],
}
});
Expand Down

0 comments on commit e4c86ca

Please sign in to comment.