Skip to content
This repository has been archived by the owner on Sep 27, 2023. It is now read-only.

Commit

Permalink
feat: full esm support for code artifacts (transform require statemen…
Browse files Browse the repository at this point in the history
…ts emitted from relay-compiler) (#269)

* wip: collect inline require statements and convert them to top level imports

* add tests (#1)

* Update CHANGELOG.md [skip ci]

* Bump version to: 13.0.3 [skip ci]

* chore: bump typescript from 4.1.4 to 4.1.5 (#268)

Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.1.4 to 4.1.5.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](microsoft/TypeScript@v4.1.4...v4.1.5)

Signed-off-by: dependabot-preview[bot] <[email protected]>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* Update CHANGELOG.md [skip ci]

* Bump version to: 13.0.4 [skip ci]

* chore: bump @types/node from 14.14.25 to 14.14.28

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.25 to 14.14.28.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* fix: revert breaking changes introduced in 13.0.3 (#274)

* Revert "refactor: use factory functions instead of deprecated functions"

This reverts commit 812d17e.

* Revert "refactor: remove deprecated typescript function calls in favor of the factory; replace @ts-ignores with proper code (microsoft/TypeScript#40263 (comment))"

This reverts commit 55c58be.

* Revert "refactor: some of the statements are redundant. It is not necessary to write to write only properties."

This reverts commit 2cbd1de.

* Revert "refactor: address all the typescript deprecations by using the factory"

This reverts commit 72e0b4a.

* chore: run CI github action on pull request

* fix: typo

* Update CHANGELOG.md [skip ci]

* Bump version to: 13.0.5 [skip ci]

* Update CHANGELOG.md [skip ci]

* Bump version to: 13.0.6 [skip ci]

* feat: include .d.ts types in release (#309)

* feat: drop typescript 3 and Node.js 10 support (#275)

* refactor: address all the typescript deprecations by using the factory

* refactor: some of the statements are redundant. It is not necessary to write to write only properties.

* refactor: remove deprecated typescript function calls in favor of the factory; replace @ts-ignores with proper code (microsoft/TypeScript#40263 (comment))

* refactor: use factory functions instead of deprecated functions

* feat: bump peerDependencies version

* dps: upgrade to latest typescript version

* chore: replace rm with rimraf for cross platform support

* chore: replace fixture tests with inline snapshot tests

* docs: add notice about minimum TypeScript version.

* chore: drop node 10 support

* Update CHANGELOG.md [skip ci]

* Bump version to: 13.0.7 [skip ci]

* Update CHANGELOG.md [skip ci]

* Bump version to: 13.0.8 [skip ci]

* feat: replace require calls by static (top level) or dynamic imports based on ts compiler options

* feat: add tests for require call replacement logic

* chore: add comment

* fix: parse contents of tsconfig file into compiler options

Converts strings to enum values etc.

* fix: remove support for dynamic imports

* fix: import default

Co-authored-by: Eloy Durn <[email protected]>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Laurin Quast <[email protected]>
Co-authored-by: Sibelius Seraphini <[email protected]>
Co-authored-by: Tim Griesser <[email protected]>
Co-authored-by: Erik Müller <[email protected]>

* please the holy linter

* chore(docs): mention es2015 module syntax of generated code

* chore: remove duplicate import

Co-authored-by: Erik Müller <[email protected]>
Co-authored-by: Eloy Durn <[email protected]>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Sibelius Seraphini <[email protected]>
Co-authored-by: Tim Griesser <[email protected]>
Co-authored-by: Erik Müller <[email protected]>
Co-authored-by: Erik Müller <[email protected]>
  • Loading branch information
8 people authored Aug 2, 2021
1 parent 76d6e70 commit fde5992
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 85 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ to instruct `babel-plugin-relay` to use in your `.babelrc`:

### TypeScript

Also be sure to configure the TypeScript compiler to transpile to `es2015`
modules and leave transpilation to `commonjs` modules up to Babel with the
following `tsconfig.json` settings:
Also be sure to configure the TypeScript compiler to transpile to `ES2015`
modules (or higher) and leave transpilation to `CommonJS` modules (if required)
up to Babel with the following `tsconfig.json` settings:

```json
```json5
{
"compilerOptions": {
"target": "es2015",
"module": "es2015"
"module": "ES2015", // ES2015 or higher
"target": "ES2020" // best use the highest target setting compatible with your Babel setup
}
}
```
Expand All @@ -68,13 +68,13 @@ react_relay_1.createFragmentContainer(
);
```

and this makes it impossible for `babel-plugin-relay` to find the locations
which makes it impossible for `babel-plugin-relay` to find the locations
where the `graphql` function is being used.

Note that this does mean you need to configure Babel to transform the ES module
`import` and `export` statements, by using the
[`babel-plugin-transform-es2015-modules-commonjs`](https://babeljs.io/docs/plugins/transform-es2015-modules-commonjs/)
transform plugin, if you’re not already.
*The generated code uses ES2015 module syntax if `module` is set to ES2015 or
higher in your `tsconfig.json`. Note that the `eagerESModules` option from
`relay-compiler` has no effect on the generated code if `module` is ES2015 or
higher.*

## Problems

Expand Down
14 changes: 7 additions & 7 deletions src/FindGraphQLTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as util from "util";

import {
GraphQLTag,
GraphQLTagFinder
GraphQLTagFinder,
} from "relay-compiler/lib/language/RelayLanguagePluginInterface";

function isCreateContainerFunction(
Expand Down Expand Up @@ -65,7 +65,7 @@ function visit(node: ts.Node, addGraphQLTag: (tag: GraphQLTag) => void): void {
break;
}
if (ts.isObjectLiteralExpression(fragmentSpec)) {
fragmentSpec.properties.forEach(prop => {
fragmentSpec.properties.forEach((prop) => {
invariant(
ts.isPropertyAssignment(prop) &&
prop.questionToken == null &&
Expand All @@ -90,7 +90,7 @@ function visit(node: ts.Node, addGraphQLTag: (tag: GraphQLTag) => void): void {
addGraphQLTag({
keyName: (propAssignment.name as ts.Identifier).text,
template: getGraphQLText(taggedTemplate),
sourceLocationOffset: getSourceLocationOffset(taggedTemplate)
sourceLocationOffset: getSourceLocationOffset(taggedTemplate),
});
});
} else {
Expand All @@ -111,7 +111,7 @@ function visit(node: ts.Node, addGraphQLTag: (tag: GraphQLTag) => void): void {
addGraphQLTag({
keyName: null,
template: getGraphQLText(taggedTemplate),
sourceLocationOffset: getSourceLocationOffset(taggedTemplate)
sourceLocationOffset: getSourceLocationOffset(taggedTemplate),
});
}
// Visit remaining arguments
Expand All @@ -130,7 +130,7 @@ function visit(node: ts.Node, addGraphQLTag: (tag: GraphQLTag) => void): void {
addGraphQLTag({
keyName: null,
template: getGraphQLText(taggedTemplate),
sourceLocationOffset: getSourceLocationOffset(taggedTemplate)
sourceLocationOffset: getSourceLocationOffset(taggedTemplate),
});
}
}
Expand Down Expand Up @@ -167,7 +167,7 @@ function getSourceLocationOffset(quasi: ts.TaggedTemplateExpression) {
const loc = quasi.getSourceFile().getLineAndCharacterOfPosition(pos);
return {
line: loc.line + 1,
column: loc.character + 1
column: loc.character + 1,
};
}

Expand All @@ -180,6 +180,6 @@ function invariant(condition: boolean, msg: string, ...args: any[]) {
export const find: GraphQLTagFinder = (text, filePath) => {
const result: GraphQLTag[] = [];
const ast = ts.createSourceFile(filePath, text, ts.ScriptTarget.Latest, true);
visit(ast, tag => result.push(tag));
visit(ast, (tag) => result.push(tag));
return result;
};
85 changes: 75 additions & 10 deletions src/formatGeneratedModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,63 @@ import { FormatModule } from "relay-compiler";
import * as ts from "typescript";
import addAnyTypeCast from "./addAnyTypeCast";

const createRequireRegex = () => /require\('(.*)'\)/g;

function getModuleName(path: string) {
const [moduleName] = path.replace("./", "").split(".");
return moduleName;
}

// collects all require calls and converts them top-level imports
const requireToImport = (content: string): string => {
const requireRegex = createRequireRegex();

// collect all require paths (unique)
const requirePaths = new Set<string>();
while (true) {
const res = requireRegex.exec(content);
if (res === null) {
break;
}
requirePaths.add(res[1]);
}
// replace all require paths
Array.from(requirePaths).forEach((requirePath) => {
content = content.replace(
`require('${requirePath}')`,
getModuleName(requirePath)
);
});
// create top-level imports
const topLevelImports = Array.from(requirePaths)
.sort()
.map(
(requirePath) =>
`import ${getModuleName(requirePath)} from "${requirePath.replace(
".ts",
""
)}";`
);
// add top-level imports
content = `${topLevelImports.join("\n")}
${content}`;
return content;
};

type FormatContentOptions = {
replaceRequire: boolean;
};

function formatContent(
rawContent: string,
options: FormatContentOptions
): string {
if (!options.replaceRequire) {
return rawContent;
}
return requireToImport(rawContent);
}

export const formatterFactory = (
compilerOptions: ts.CompilerOptions = {}
): FormatModule => ({
Expand All @@ -11,27 +68,35 @@ export const formatterFactory = (
concreteText,
typeText,
hash,
sourceHash
sourceHash,
}) => {
const { noImplicitAny, module = -1 } = compilerOptions;

const documentTypeImport = documentType
? `import { ${documentType} } from "relay-runtime";`
: "";
const docTextComment = docText ? "\n/*\n" + docText.trim() + "\n*/\n" : "";
let nodeStatement = `const node: ${documentType ||
"never"} = ${concreteText};`;
if (compilerOptions.noImplicitAny) {
let nodeStatement = `const node: ${
documentType || "never"
} = ${concreteText};`;
if (noImplicitAny) {
nodeStatement = addAnyTypeCast(nodeStatement).trim();
}
return `/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
${hash ? `/* ${hash} */\n` : ""}
${documentTypeImport}
${typeText || ""}
const rawContent = `${typeText || ""}
${docTextComment}
${nodeStatement}
(node as any).hash = '${sourceHash}';
export default node;
`;

const content = `/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
${hash ? `/* ${hash} */\n` : ""}
${documentTypeImport}
${formatContent(rawContent, {
replaceRequire: module >= ts.ModuleKind.ES2015,
})}`;
return content;
};
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export default function plugin(): PluginInterface {
outputExtension: "ts",
findGraphQLTags: find,
formatModule: formatterFactory(loadCompilerOptions()),
typeGenerator: TypeScriptGenerator
typeGenerator: TypeScriptGenerator,
};
}
15 changes: 12 additions & 3 deletions src/loadCompilerOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@ export const loadCompilerOptions = (): ts.CompilerOptions => {
if (!configFileName) {
return {};
}
const result = ts.readConfigFile(configFileName, ts.sys.readFile);
if (result.error) {
const configFile = ts.readConfigFile(configFileName, ts.sys.readFile);
if (configFile.error) {
return {};
}
return result.config.compilerOptions;
// parse config file contents (to convert strings to enum values etc.)
const parsedConfig = ts.parseJsonConfigFileContent(
configFile.config,
ts.sys,
"./"
);
if (parsedConfig.errors.length > 0) {
return {};
}
return parsedConfig.options;
};
8 changes: 4 additions & 4 deletions test/FindGraphQLTags-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ describe("FindGraphQLTags", () => {
name
}
`,
sourceLocationOffset: { line: 5, column: 16 }
}
sourceLocationOffset: { line: 5, column: 16 },
},
]);
});

Expand All @@ -38,8 +38,8 @@ describe("FindGraphQLTags", () => {
{
keyName: null,
template: `fragment TestModule_artist on Artist {name}`,
sourceLocationOffset: { line: 1, column: 8 }
}
sourceLocationOffset: { line: 1, column: 8 },
},
]);
});
// TODO: Cover all cases where tags are extracted
Expand Down
Loading

0 comments on commit fde5992

Please sign in to comment.