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

implement bundling changes suggested in #4062 #4096

Open
wants to merge 13 commits into
base: 16.x.x
Choose a base branch
from
49 changes: 48 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,55 @@
"description": "A Query Language and Runtime which can target any service.",
"license": "MIT",
"private": true,
"main": "index",
"main": "index.js",
"module": "index.mjs",
"exports": {
".": {
"types": {
"import": "./index.js.d.mts",
"default": "./index.d.ts"
},
"module": "./index.mjs",
"import": "./index.js.mjs",
"default": "./index.js"
},
yaacovCR marked this conversation as resolved.
Show resolved Hide resolved
"./execution/execute.js": {
"types": {
"import": "./execution/execute.js.d.mts",
"default": "./execution/execute.d.ts"
},
"module": "./execution/execute.mjs",
"import": "./execution/execute.js.mjs",
"default": "./execution/execute.js"
},
"./jsutils/instanceOf.js": {
"types": {
"import": "./jsutils/instanceOf.js.d.mts",
"default": "./jsutils/instanceOf.d.ts"
},
"module": "./jsutils/instanceOf.mjs",
"import": "./jsutils/instanceOf.js.mjs",
"default": "./jsutils/instanceOf.js"
},
"./language/parser.js": {
"types": {
"import": "./language/parser.js.d.mts",
"default": "./language/parser.d.ts"
},
"module": "./language/parser.mjs",
"import": "./language/parser.js.mjs",
"default": "./language/parser.js"
},
"./language/ast.js": {
"types": {
"import": "./language/ast.js.d.mts",
"default": "./language/ast.d.ts"
},
"module": "./language/ast.mjs",
"import": "./language/ast.js.mjs",
"default": "./language/ast.js"
}
},
"typesVersions": {
">=4.1.0": {
"*": [
Expand Down
147 changes: 147 additions & 0 deletions resources/build-npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ const {
showDirStats,
} = require('./utils.js');

const entryPoints = [
'index.ts',
'execution/execute.ts',
'jsutils/instanceOf.ts',
'language/parser.ts',
'language/ast.ts',
];
phryneas marked this conversation as resolved.
Show resolved Hide resolved

if (require.main === module) {
fs.rmSync('./npmDist', { recursive: true, force: true });
fs.mkdirSync('./npmDist');
Expand Down Expand Up @@ -57,11 +65,21 @@ if (require.main === module) {

const tsProgram = ts.createProgram(['src/index.ts'], tsOptions, tsHost);
const tsResult = tsProgram.emit();

assert(
!tsResult.emitSkipped,
'Fail to generate `*.d.ts` files, please run `npm run check`',
);

for (const [filename, contents] of Object.entries(
buildCjsEsmWrapper(
entryPoints.map((e) => './src/' + e),
tsProgram,
),
)) {
writeGeneratedFile(filename, contents);
}

assert(packageJSON.types === undefined, 'Unexpected "types" in package.json');
const supportedTSVersions = Object.keys(packageJSON.typesVersions);
assert(
Expand Down Expand Up @@ -107,6 +125,8 @@ function buildPackageJSON() {
delete packageJSON.scripts;
delete packageJSON.devDependencies;

packageJSON.type = 'commonjs';
yaacovCR marked this conversation as resolved.
Show resolved Hide resolved

// TODO: move to integration tests
const publishTag = packageJSON.publishConfig?.tag;
assert(publishTag != null, 'Should have packageJSON.publishConfig defined!');
Expand Down Expand Up @@ -137,3 +157,130 @@ function buildPackageJSON() {

return packageJSON;
}

/**
*
* @param {string[]} files
* @param {ts.Program} tsProgram
* @returns
*/
function buildCjsEsmWrapper(files, tsProgram) {
/**
* @type {Record<string, string>} inputFiles
*/
const inputFiles = {};
for (const file of files) {
const sourceFile = tsProgram.getSourceFile(file);
assert(sourceFile, `No source file found for ${file}`);

const generatedFileName = path.relative(
path.dirname(tsProgram.getRootFileNames()[0]),
file.replace(/\.ts$/, '.js.mts'),
);
const exportFrom = ts.factory.createStringLiteral(
'./' + path.basename(file, '.ts') + '.js',
);

/**
* @type {ts.Statement[]}
*/
const statements = [];

/** @type {string[]} */
const exports = [];

/** @type {string[]} */
const typeExports = [];

sourceFile.forEachChild((node) => {
if (ts.isExportDeclaration(node)) {
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
for (const element of node.exportClause.elements) {
if (node.isTypeOnly || element.isTypeOnly) {
typeExports.push(element.name.text);
} else {
exports.push(element.name.text);
}
}
}
} else if (
node.modifiers?.some(
(modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword,
)
) {
if (ts.isVariableStatement(node)) {
for (const declaration of node.declarationList.declarations) {
if (declaration.name && ts.isIdentifier(declaration.name)) {
exports.push(declaration.name.text);
}
}
} else if (
ts.isFunctionDeclaration(node) ||
ts.isClassDeclaration(node)
) {
exports.push(node.name.text);
} else if (ts.isTypeAliasDeclaration(node)) {
typeExports.push(node.name.text);
}
}
});
if (exports.length > 0) {
statements.push(
ts.factory.createExportDeclaration(
undefined,
undefined,
false,
ts.factory.createNamedExports(
exports.map((name) =>
ts.factory.createExportSpecifier(false, undefined, name),
),
),
exportFrom,
),
);
}
if (typeExports.length > 0) {
statements.push(
ts.factory.createExportDeclaration(
undefined,
undefined,
true,
ts.factory.createNamedExports(
typeExports.map((name) =>
ts.factory.createExportSpecifier(false, undefined, name),
),
),
exportFrom,
),
);
}
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
inputFiles[generatedFileName] = printer.printFile(
ts.factory.createSourceFile(
statements,
ts.factory.createToken(ts.SyntaxKind.EndOfFileToken),
ts.NodeFlags.None,
),
);
}
/**
* @type {ts.CompilerOptions} options
*/
const options = {
...tsProgram.getCompilerOptions(),
declaration: true,
emitDeclarationOnly: false,
isolatedModules: true,
module: ts.ModuleKind.ESNext,
};
options.outDir = options.declarationDir;
const results = {};
const host = ts.createCompilerHost(options);
host.writeFile = (fileName, contents) => (results[fileName] = contents);
host.readFile = (fileName) => inputFiles[fileName];

const program = ts.createProgram(Object.keys(inputFiles), options, host);
program.emit();

return results;
}
11 changes: 11 additions & 0 deletions src/execution/execute.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`:
* * ExecutionContext
* * assertValidExecutionArguments @internal
* * buildExecutionContext @internal
* * buildResolveInfo @internal
* * getFieldDef @internal
* Should we still expose this file?
*/

import { devAssert } from '../jsutils/devAssert';
import { inspect } from '../jsutils/inspect';
import { invariant } from '../jsutils/invariant';
Expand Down
6 changes: 6 additions & 0 deletions src/execution/values.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`: none
* Should we still expose this file?
*/

import { inspect } from '../jsutils/inspect';
import { keyMap } from '../jsutils/keyMap';
import type { Maybe } from '../jsutils/Maybe';
Expand Down
4 changes: 4 additions & 0 deletions src/jsutils/Maybe.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
/**
* Quoted as "used by external libraries".
* Should we still expose these?
*/
/** Conveniently represents flow's "Maybe" type https://flow.org/en/docs/types/maybe/ */
export type Maybe<T> = null | undefined | T;
6 changes: 6 additions & 0 deletions src/jsutils/ObjMap.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* Quoted as "used by external libraries".
* All of these could be replaced by Record<string, T> or Readonly<Record<string, T>>
* Should we still expose these?
*/

export interface ObjMap<T> {
[key: string]: T;
}
Expand Down
4 changes: 4 additions & 0 deletions src/jsutils/PromiseOrValue.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
/**
* Quoted as "used by external libraries".
* Should we still expose these?
*/
export type PromiseOrValue<T> = Promise<T> | T;
7 changes: 7 additions & 0 deletions src/language/ast.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`:
* * isNode @internal
* * QueryDocumentKeys @internal
* Should we still expose this file?
*/
import type { Kind } from './kinds';
import type { Source } from './source';
import type { TokenKind } from './tokenKind';
Expand Down
7 changes: 7 additions & 0 deletions src/language/lexer.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`:
* * isPunctuatorTokenKind @internal
* Should we still expose this file?
*/

import { syntaxError } from '../error/syntaxError';

import { Token } from './ast';
Expand Down
7 changes: 7 additions & 0 deletions src/language/parser.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`:
* * Parser @internal
* Should we still expose this file?
*/

import type { Maybe } from '../jsutils/Maybe';

import type { GraphQLError } from '../error/GraphQLError';
Expand Down
7 changes: 7 additions & 0 deletions src/type/schema.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`:
* * GraphQLSchemaNormalizedConfig @internal
* * GraphQLSchemaValidationOptions
* Should we still expose this file?
*/
import { devAssert } from '../jsutils/devAssert';
import { inspect } from '../jsutils/inspect';
import { instanceOf } from '../jsutils/instanceOf';
Expand Down
10 changes: 10 additions & 0 deletions src/validation/ValidationContext.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`:
* * ASTValidationContext
* * ASTValidationRule
* * SDLValidationContext
* * SDLValidationRule
* Should we still expose this file?
*/

import type { Maybe } from '../jsutils/Maybe';
import type { ObjMap } from '../jsutils/ObjMap';

Expand Down
7 changes: 7 additions & 0 deletions src/validation/specifiedRules.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`:
* * specifiedSDLRules @internal
* Should we still expose this file?
*/

// Spec Section: "Executable Definitions"
import { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule';
// Spec Section: "Field Selections on Objects, Interfaces, and Unions Types"
Expand Down
9 changes: 9 additions & 0 deletions src/validation/validate.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/**
* Quoted as "used by external libraries".
* Missing exports from `graphql`:
* * assertValidSDL @internal
* * assertValidSDLExtension @internal
* * validateSDL @internal
* Should we still expose this file?
*/

import { devAssert } from '../jsutils/devAssert';
import type { Maybe } from '../jsutils/Maybe';

Expand Down