-
-
Notifications
You must be signed in to change notification settings - Fork 254
Disallow duplicate named exports #107
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -844,7 +844,7 @@ pp.parseExport = function (node) { | |
} | ||
node.declaration = expr; | ||
if (needsSemi) this.semicolon(); | ||
this.checkExport(node); | ||
this.checkExport(node, true, true); | ||
return this.finishNode(node, "ExportDefaultDeclaration"); | ||
} else if (this.state.type.keyword || this.shouldParseExportDeclaration()) { | ||
node.specifiers = []; | ||
|
@@ -855,7 +855,7 @@ pp.parseExport = function (node) { | |
node.specifiers = this.parseExportSpecifiers(); | ||
this.parseExportFrom(node); | ||
} | ||
this.checkExport(node); | ||
this.checkExport(node, true); | ||
return this.finishNode(node, "ExportNamedDeclaration"); | ||
}; | ||
|
||
|
@@ -903,7 +903,31 @@ pp.shouldParseExportDeclaration = function () { | |
return this.isContextual("async"); | ||
}; | ||
|
||
pp.checkExport = function (node) { | ||
pp.checkExport = function (node, checkNames, isDefault) { | ||
if (checkNames) { | ||
// Check for duplicate exports | ||
if (isDefault) { | ||
// Default exports | ||
this.checkDuplicateExports(node, "default", isDefault); | ||
} else if (node.specifiers && node.specifiers.length) { | ||
// Named exports | ||
for (let specifier of node.specifiers) { | ||
const name = specifier.exported.name; | ||
if (name === "default") isDefault = true; | ||
this.checkDuplicateExports(specifier, name, isDefault); | ||
} | ||
} else if (node.declaration) { | ||
// Exported declarations | ||
if (node.declaration.type === "FunctionDeclaration" || node.declaration.type === "ClassDeclaration") { | ||
this.checkDuplicateExports(node, node.declaration.id.name, isDefault); | ||
} else if (node.declaration.type === "VariableDeclaration") { | ||
for (let declaration of node.declaration.declarations) { | ||
this.checkDuplicateExports(declaration, declaration.id.name, isDefault); | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (this.state.decorators.length) { | ||
let isClass = node.declaration && (node.declaration.type === "ClassDeclaration" || node.declaration.type === "ClassExpression"); | ||
if (!node.declaration || !isClass) { | ||
|
@@ -913,6 +937,20 @@ pp.checkExport = function (node) { | |
} | ||
}; | ||
|
||
pp.checkDuplicateExports = function(node, name, isDefault) { | ||
if (this.state.exportedIdentifiers[name]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to manage Something along the lines of this maybe? if (Object.getOwnPropertyNames(this.state.exportedIdentifiers).indexOf(name) !== -1) { There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, I wrap up a fix There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah interesting, thanks for the report cc @kaicataldo There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh wow, that makes sense. @danez Let me know if you need me work on a fix - happy to do it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue in jscs-dev/node-jscs#1204 😄 |
||
this.raiseDuplicateExportError(node, name, isDefault); | ||
} | ||
this.state.exportedIdentifiers[name] = true; | ||
}; | ||
|
||
pp.raiseDuplicateExportError = function(node, name, isDefault) { | ||
this.raise(node.start, isDefault ? | ||
"Only one default export allowed per module." : | ||
`\`${name}\` has already been exported. Exported identifiers must be unique.` | ||
); | ||
}; | ||
|
||
// Parses a comma-separated list of module exports. | ||
|
||
pp.parseExportSpecifiers = function () { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export default function() {}; | ||
export { foo as default }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"throws": "Only one default export allowed per module. (2:9)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export default {}; | ||
export default function() {}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"throws": "Only one default export allowed per module. (2:0)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { Foo }; | ||
export class Foo {}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"throws": "`Foo` has already been exported. Exported identifiers must be unique. (2:0)" | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { foo }; | ||
export function foo() {}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"throws": "`foo` has already been exported. Exported identifiers must be unique. (2:0)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { foo }; | ||
export const foo = bar; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"throws": "`foo` has already been exported. Exported identifiers must be unique. (2:13)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { foo }; | ||
export { bar as foo }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"throws": "`foo` has already been exported. Exported identifiers must be unique. (2:9)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
export interface foo { p: number }; | ||
export interface foo<T> { p: T }; | ||
export interface bar<T> { p: T }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty new to Flow - let me know if this isn't the correct fix for this test There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is correct |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a thought: might be nice if this method wasn't taking in true, true (an object, named, etc) but I know we do that everywhere else ^
this.parseFunction(expr, true, false, false, true);
😄There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, was trying to follow the style I saw elsewhere, but agree. Would you like me to change that to an object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hzoo: Do you mean
checkExport(node: Node, options: { named: boolean, default: boolean })
or what do you mean with object? Maybe alsocheckExport(node: Node, type: "named" | "default" | null)
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah to make it more readable - dono if it was done before for perf?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assumed it was done this way for performance reasons