UNPKG

atom-nuclide

Version:

A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.

139 lines (118 loc) 3.99 kB
'use strict'; /* @noflow */ /* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ /* NON-TRANSPILED FILE */ /* eslint-disable babel/func-params-comma-dangle, prefer-object-spread/prefer-object-spread */ // This rule is here because of a babel 5 bug, where "export type" is treated // as a value export. This results in the types file getting required. In most // cases, the types file gets transpiled to a mostly empty file (because types // get removed), so there's only a small perf cost. However, there is some flow // syntax that is not supported by babel 5 (e.g. "export interface") that // results in the transpiler throwing at runtime. // import foo from './foo'; <- will get required // export type {foo}; <- will get exported // export type bar = {}; <- will NOT get exported // import type bar from './bar'; <- will NOT get required // export type {bar}; <- will get exported // export type {baz} from './baz'; <- will get required and exported const assert = require('assert'); module.exports = function(context) { const aliasTypeExport = []; const namedTypeExports = []; const valueExports = []; // TODO(asuarez): Write tests for "includeTypeAlias" mode and turn it on. // const includeTypeAlias = context.options.indexOf('includeTypeAlias') !== -1; const includeTypeAlias = false; function isImportType(name, moduleScope) { assert(moduleScope.type === 'module'); for (const variable of moduleScope.variables) { if (variable.name === name) { for (const def of variable.defs) { if (def.type === 'ImportBinding' && ( def.parent.importKind === 'type' || def.parent.importKind === 'typeof' ) ) { return true; } } } } return false; } return { ExportAllDeclaration(node) { // export * from …; valueExports.push(node); }, ExportDefaultDeclaration(node) { // export default 1; // export default function () {}; valueExports.push(node); }, ExportNamedDeclaration(node) { if (node.exportKind === 'type') { if (node.declarations) { // export type … = …; aliasTypeExport.push(node); } else { // export type …; // export type … from …; namedTypeExports.push(node); } } else if (node.exportKind === 'value') { valueExports.push(node); } }, 'Program:exit'(node) { if (valueExports.length === 0) { // This is probably a types file... return; } if (includeTypeAlias) { for (const typeExport of [aliasTypeExport, namedTypeExports]) { for (const typeNode of typeExport) { context.report({ node: typeNode, message: 'Unexpected type exporting.', }); } } return; } for (const typeNode of namedTypeExports) { // export type … from …; if (typeNode.source !== null) { context.report({ node: typeNode, message: 'Unexpected type re-exporting. ' + 'Import the type where it\'s used instead.', }); } // export type …; const moduleScope = context.getScope().childScopes[0]; for (const specifier of typeNode.specifiers) { if (isImportType(specifier.local.name, moduleScope)) { context.report({ node: specifier, message: 'Unexpected type re-exporting. ' + 'Import the type where it\'s used instead.', }); } } } }, }; }; module.exports.schema = [ { enum: ['includeTypeAlias'], }, ];