Skip to content

Commit

Permalink
Added flow support. Ignore editor config folder.
Browse files Browse the repository at this point in the history
  • Loading branch information
Yusinto Ngadiman authored and Yusinto Ngadiman committed Nov 9, 2017
1 parent dfd0cbb commit 9c6baaf
Show file tree
Hide file tree
Showing 11 changed files with 390 additions and 5 deletions.
12 changes: 12 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[ignore]
<PROJECT_ROOT>/bin/.*
<PROJECT_ROOT>/build/.*
<PROJECT_ROOT>/example/.*
<PROJECT_ROOT>/lib/.*

[include]
./src/.*

[libs]

[options]
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,4 @@ typings/
# dotenv environment variables file
.env

.idea
66 changes: 66 additions & 0 deletions lib/compiler/formatGeneratedModule.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Changes have been made to this file.
*
* devOnlyText have been removed because the variable __DEV__ is not guaranteed
* to be available on the consumer end.
*
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule formatGeneratedModule
* @flow
* @format
*/

'use strict';

export type FormatModule = ({|
moduleName: string,
documentType: 'ConcreteBatch' | 'ConcreteFragment',
docText: ?string,
concreteText: string,
flowText: ?string,
hash: ?string,
devTextGenerator: (objectName: string) => string,
relayRuntimeModule: string,
|}) => string;

const formatGeneratedModule: FormatModule = ({
moduleName,
documentType,
docText,
concreteText,
flowText,
hash,
devTextGenerator,
relayRuntimeModule,
}) => {
const objectName = documentType === 'ConcreteBatch' ? 'batch' : 'fragment';
const docTextComment = docText ? '\n/*\n' + docText.trim() + '\n*/\n' : '';
const hashText = hash ? `\n * ${hash}` : '';
// const devOnlyText = devTextGenerator ? devTextGenerator(objectName) : '';
return `/**
* ${'@'}flow${hashText}
*/

/* eslint-disable */

'use strict';

/*::
import type {${documentType}} from '${relayRuntimeModule}';
${flowText || ''}
*/

${docTextComment}
const ${objectName} /*: ${documentType}*/ = ${concreteText};

module.exports = ${objectName};
`;
};

module.exports = formatGeneratedModule;
121 changes: 121 additions & 0 deletions lib/compiler/main.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// @flow
import yargs from 'yargs';

import 'babel-polyfill';
import {promisify} from 'util';
import path from 'path';
import fs from 'fs';
import crypto from 'crypto';
import RelayCompiler from 'relay-compiler';
import {getFilepathsFromGlob, getRelayFileWriter, getSchema} from './ripped';

const {
ConsoleReporter,
Runner: CodegenRunner,
FileIRParser: RelayJSModuleParser,
} = RelayCompiler;
const queryCache = [];
const writeFileAsync = promisify(fs.writeFile);

// Ripped from relay-compiler/RelayFileWriter.js
function md5(x: string): string {
return crypto
.createHash('md5')
.update(x, 'utf8')
.digest('hex');
}

function persistQuery(operationText: string): Promise<string> {
return new Promise((resolve) => {
const queryId = md5(operationText);
queryCache.push({id: queryId, text: operationText});
console.log(`mapped ${operationText} to ${queryId}`);
resolve(queryId);
});
}

/*
* Most of the code in this run method are ripped from:
* relay-compiler/bin/RelayCompilerBin.js
*/
async function run(options: { schema: string, src: string}) {
const srcDir = path.resolve(process.cwd(), options.src);
const schemaPath = path.resolve(process.cwd(), options.schema);
console.log(`srcDir: ${srcDir}, schemaPath: ${schemaPath}`);

const reporter = new ConsoleReporter({verbose: true});
const parserConfigs = {
default: {
baseDir: srcDir,
getFileFilter: RelayJSModuleParser.getFileFilter,
getParser: RelayJSModuleParser.getParser,
getSchema: () => getSchema(schemaPath),
filepaths: getFilepathsFromGlob(srcDir, {
extensions: ['js'],
include: ['**'],
exclude: [
'**/node_modules/**',
'**/__mocks__/**',
'**/__tests__/**',
'**/__generated__/**',
]
}),
},
};
const writerConfigs = {
default: {
getWriter: getRelayFileWriter(srcDir, persistQuery),
isGeneratedFile: (filePath) =>
filePath.endsWith('.js') && filePath.includes('__generated__'),
parser: 'default',
},
};
const codegenRunner = new CodegenRunner({
reporter,
parserConfigs,
writerConfigs,
onlyValidate: false,
});

// the real work is done here
const result = await codegenRunner.compileAll();

const queryCacheOutputFile = `${srcDir}/queryMap.json`;
try {
await writeFileAsync(queryCacheOutputFile, JSON.stringify(queryCache));
console.log(`Query cache written to: ${queryCacheOutputFile}`);
} catch (err) {
if (err) {
return console.log(err);
}
}

console.log(`Done! ${result}`);
}

// Collect args
const argv = yargs
.usage(`Usage: $0 --schema <path-to-schema> --src <path-to-src-dir>`)
.options({
schema: {
describe: 'Path to schema.graphql or schema.json',
demandOption: true,
type: 'string',
},
src: {
describe: 'Root directory of application code',
demandOption: true,
type: 'string',
},
})
.help().argv;

(async function () {
console.log(`Starting relay compilation`);
try {
await run(argv);
} catch (err) {
console.log(`error: ${err}`);
process.exit(1);
}
})();
110 changes: 110 additions & 0 deletions lib/compiler/ripped.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* The code in this file are ripped from:
* relay-compiler/bin/RelayCompilerBin.js
*
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @flow
* @providesModule RelayCompilerBin
* @format
*/

import fs from 'fs';
import path from 'path';
import {
buildASTSchema,
buildClientSchema,
parse,
printSchema,
} from 'graphql';
import type {GraphQLSchema} from 'graphql';
import RelayCompiler from 'relay-compiler';
import formatGeneratedModule from './formatGeneratedModule';

const {
FileWriter: RelayFileWriter,
IRTransforms: RelayIRTransforms,
} = RelayCompiler;

const {
codegenTransforms,
fragmentTransforms,
printTransforms,
queryTransforms,
schemaExtensions,
} = RelayIRTransforms;

export function getFilepathsFromGlob(baseDir: string,
options: {
extensions: Array<string>,
include: Array<string>,
exclude: Array<string>,
},): Array<string> {
const {extensions, include, exclude} = options;
const patterns = include.map(inc => `${inc}/*.+(${extensions.join('|')})`);

const glob = require('fast-glob');
return glob.sync(patterns, {
cwd: baseDir,
bashNative: [],
onlyFiles: true,
ignore: exclude,
});
}

// Note: this function has been modified from its original form.
// persistQuery param is added
export function getRelayFileWriter(baseDir: string, persistQuery: (operationText: string) => Promise<string>) {
return (onlyValidate: boolean, schema: GraphQLSchema, documents: any, baseDocuments: any) =>
new RelayFileWriter({
config: {
baseDir,
compilerTransforms: {
codegenTransforms,
fragmentTransforms,
printTransforms,
queryTransforms,
},
customScalars: {},
formatModule: formatGeneratedModule,
inputFieldWhiteListForFlow: [],
schemaExtensions,
useHaste: false,
persistQuery,
},
onlyValidate,
schema,
baseDocuments,
documents,
});
}

export function getSchema(schemaPath: string): GraphQLSchema {
try {
let source = fs.readFileSync(schemaPath, 'utf8');
if (path.extname(schemaPath) === '.json') {
source = printSchema(buildClientSchema(JSON.parse(source).data));
}
source = `
directive @include(if: Boolean) on FRAGMENT | FIELD
directive @skip(if: Boolean) on FRAGMENT | FIELD

${source}
`;
return buildASTSchema(parse(source));
} catch (error) {
throw new Error(
`
Error loading schema. Expected the schema to be a .graphql or a .json
file, describing your GraphQL server's API. Error detail:

${error.stack}
`.trim(),
);
}
}
5 changes: 5 additions & 0 deletions lib/exports/index.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import matchQueryMiddleware from './matchQueryMiddleware';

module.exports = {
matchQueryMiddleware,
};
22 changes: 22 additions & 0 deletions lib/exports/matchQueryMiddleware.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import bodyParser from 'body-parser';

const jsonParser = bodyParser.json();

export default function matchQueryMiddleware(queryMapJson) {
return (req, res, next) => {
return jsonParser(req, res, () => {
const queryId = req.body.queryId;
if (queryId) {
console.log(`Mapping queryId: ${queryId}`);
const query = queryMapJson.find(q => q.id === queryId);
if (query) {
console.log(`Yayy! Found persisted query ${queryId}`);
req.body.query = query.text;
} else {
console.error(`ERROR: can't find queryId: ${queryId}`);
}
}
next();
});
};
};
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
"relay-compiler-plus": "bin/relay-compiler-plus"
},
"scripts": {
"flow": "flow",
"build-compiler": "NODE_ENV=production node build && exec 3<> bin/relay-compiler-plus && awk -v TEXT='#!/usr/bin/env node' 'BEGIN {print TEXT}{print}' bin/relay-compiler-plus >&3",
"build-exports": "babel src/exports -d lib",
"build": "rimraf bin/* && rimraf lib/* && npm run build-compiler && npm run build-exports"
"build-flow": "flow-copy-source -v src lib",
"clean": "rimraf bin && rimraf lib",
"build": "npm run clean && npm run build-compiler && npm run build-exports && npm run build-flow"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -47,6 +50,8 @@
"babel-preset-flow": "^6.23.0",
"babel-preset-stage-0": "^6.24.1",
"babel-register": "^6.26.0",
"flow-bin": "^0.59.0",
"flow-copy-source": "^1.2.1",
"rimraf": "^2.6.2",
"webpack": "^3.8.1",
"webpack-node-externals": "^1.6.0"
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/ripped.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const {
schemaExtensions,
} = RelayIRTransforms;

export function getFilepathsFromGlob(baseDir,
export function getFilepathsFromGlob(baseDir: string,
options: {
extensions: Array<string>,
include: Array<string>,
Expand All @@ -60,7 +60,7 @@ export function getFilepathsFromGlob(baseDir,
// Note: this function has been modified from its original form.
// persistQuery param is added
export function getRelayFileWriter(baseDir: string, persistQuery: (operationText: string) => Promise<string>) {
return (onlyValidate, schema, documents, baseDocuments) =>
return (onlyValidate: boolean, schema: GraphQLSchema, documents: any, baseDocuments: any) =>
new RelayFileWriter({
config: {
baseDir,
Expand Down
1 change: 1 addition & 0 deletions src/queryMap.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Loading

0 comments on commit 9c6baaf

Please sign in to comment.