Improve swc_ecma_trnasforms (#127)

# swc_ecma_ast
 - Add PrivateName to Expr

# swc_ecma_parser
 - Fix parsing of private name

# swc_ecma_transforms

## Hygiene
 - It correctly tracks `BindingIdentifer` / `IdentifierReference`
 - Preserve `IdentiferReference` if it conflicts with a `BindingIdentifier`

## Block scoping
 - It correctly tracks `BindingIdentifer` / `IdentifierReference`


## Fixer
 - It removes useless parens.
 - It removes useless `IdentiferReference`s in comma expressions.

## Classes properties
 - public prooperty
 - private property

## Class decorators
 - implemented
This commit is contained in:
강동윤 2019-01-29 23:56:16 +09:00 committed by GitHub
parent 90135ede1e
commit ba0c7c908c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
127 changed files with 11085 additions and 1679 deletions

View File

@ -27,10 +27,10 @@ before_install:
install:
- npm i -g jest
- cargo test --no-run --color always --all
- cargo test --no-run --color always --all --all-features
script:
- RUST_BACKTRACE=full cargo test --color always --all
- RUST_BACKTRACE=full cargo test --color always --all --all-features
before_deploy:
- CARGO_TARGET_DIR=$HOME/cargo-target cargo doc --color always

View File

@ -1,5 +1,5 @@
#!/bin/bash
set -eu
cat words.txt | uniq | sort > words_sorted.txt
cat words.txt | awk '{$1=$1};1' | uniq | sort > words_sorted.txt
mv words_sorted.txt words.txt

View File

@ -1,11 +1,564 @@
AbortController
AbortSignal
AnalyserNode
Animation
AnimationEffectReadOnly
AnimationEffectTiming
AnimationEffectTimingReadOnly
AnimationEvent
AnimationPlaybackEvent
AnimationTimeline
ApplicationCache
ApplicationCacheErrorEvent
Array
ArrayBuffer
Atomics
Attr
Audio
AudioBuffer
AudioBufferSourceNode
AudioContext
AudioDestinationNode
AudioListener
AudioNode
AudioParam
AudioProcessingEvent
AudioScheduledSourceNode
AudioWorkletGlobalScope
AudioWorkletNode
AudioWorkletProcessor
BarProp
BaseAudioContext
BatteryManager
BeforeUnloadEvent
BigInt
BigInt64Array
BigUint64Array
BiquadFilterNode
Blob
BlobEvent
Boolean
BroadcastChannel
BudgetService
ByteLengthQueuingStrategy
CSS
CSSConditionRule
CSSFontFaceRule
CSSGroupingRule
CSSImportRule
CSSKeyframeRule
CSSKeyframesRule
CSSMediaRule
CSSNamespaceRule
CSSPageRule
CSSRule
CSSRuleList
CSSStyleDeclaration
CSSStyleRule
CSSStyleSheet
CSSSupportsRule
Cache
CacheStorage
CanvasCaptureMediaStreamTrack
CanvasGradient
CanvasPattern
CanvasRenderingContext2D
ChannelMergerNode
ChannelSplitterNode
CharacterData
ClipboardEvent
CloseEvent
Comment
CompositionEvent
ConstantSourceNode
ConvolverNode
CountQueuingStrategy
Credential
CredentialsContainer
Crypto
CryptoKey
CustomElementRegistry
CustomEvent
DOMError
DOMException
DOMImplementation
DOMMatrix
DOMMatrixReadOnly
DOMParser
DOMPoint
DOMPointReadOnly
DOMQuad
DOMRect
DOMRectReadOnly
DOMStringList
DOMStringMap
DOMTokenList
DataTransfer
DataTransferItem
DataTransferItemList
DataView
Date
DelayNode
DeviceMotionEvent
DeviceOrientationEvent
Document
DocumentFragment
DocumentType
DragEvent
DynamicsCompressorNode
Element
Error
ErrorEvent
EvalError
Event
EventSource
EventTarget
File
FileList
FileReader
Float32Array
Float64Array
FocusEvent
FontFace
FontFaceSetLoadEvent
FormData
Function
GainNode
Gamepad
GamepadButton
GamepadEvent
HTMLAllCollection
HTMLAnchorElement
HTMLAreaElement
HTMLAudioElement
HTMLBRElement
HTMLBaseElement
HTMLBodyElement
HTMLButtonElement
HTMLCanvasElement
HTMLCollection
HTMLContentElement
HTMLDListElement
HTMLDataElement
HTMLDataListElement
HTMLDetailsElement
HTMLDialogElement
HTMLDirectoryElement
HTMLDivElement
HTMLDocument
HTMLElement
HTMLEmbedElement
HTMLFieldSetElement
HTMLFontElement
HTMLFormControlsCollection
HTMLFormElement
HTMLFrameElement
HTMLFrameSetElement
HTMLHRElement
HTMLHeadElement
HTMLHeadingElement
HTMLHtmlElement
HTMLIFrameElement
HTMLImageElement
HTMLInputElement
HTMLLIElement
HTMLLabelElement
HTMLLegendElement
HTMLLinkElement
HTMLMapElement
HTMLMarqueeElement
HTMLMediaElement
HTMLMenuElement
HTMLMetaElement
HTMLMeterElement
HTMLModElement
HTMLOListElement
HTMLObjectElement
HTMLOptGroupElement
HTMLOptionElement
HTMLOptionsCollection
HTMLOutputElement
HTMLParagraphElement
HTMLParamElement
HTMLPictureElement
HTMLPreElement
HTMLProgressElement
HTMLQuoteElement
HTMLScriptElement
HTMLSelectElement
HTMLShadowElement
HTMLSlotElement
HTMLSourceElement
HTMLSpanElement
HTMLStyleElement
HTMLTableCaptionElement
HTMLTableCellElement
HTMLTableColElement
HTMLTableElement
HTMLTableRowElement
HTMLTableSectionElement
HTMLTemplateElement
HTMLTextAreaElement
HTMLTimeElement
HTMLTitleElement
HTMLTrackElement
HTMLUListElement
HTMLUnknownElement
HTMLVideoElement
HashChangeEvent
Headers
History
IDBCursor
IDBCursorWithValue
IDBDatabase
IDBFactory
IDBIndex
IDBKeyRange
IDBObjectStore
IDBOpenDBRequest
IDBRequest
IDBTransaction
IDBVersionChangeEvent
IIRFilterNode
IdleDeadline
Image
ImageBitmap
ImageBitmapRenderingContext
ImageCapture
ImageData
Infinity
InputEvent
Int16Array
Int32Array
Int8Array
IntersectionObserver
IntersectionObserverEntry
Intl
JSON
KeyboardEvent
KeyframeEffect
KeyframeEffectReadOnly
Location
MIDIAccess
MIDIConnectionEvent
MIDIInput
MIDIInputMap
MIDIMessageEvent
MIDIOutput
MIDIOutputMap
MIDIPort
Map
Math
MediaDeviceInfo
MediaDevices
MediaElementAudioSourceNode
MediaEncryptedEvent
MediaError
MediaKeyMessageEvent
MediaKeySession
MediaKeyStatusMap
MediaKeySystemAccess
MediaList
MediaQueryList
MediaQueryListEvent
MediaRecorder
MediaSettingsRange
MediaSource
MediaStream
MediaStreamAudioDestinationNode
MediaStreamAudioSourceNode
MediaStreamEvent
MediaStreamTrack
MediaStreamTrackEvent
MessageChannel
MessageEvent
MessagePort
MimeType
MimeTypeArray
MouseEvent
MutationEvent
MutationObserver
MutationRecord
NODE_ENV
NaN
NamedNodeMap
NavigationPreloadManager
Navigator
NetworkInformation
Node
NodeFilter
NodeIterator
NodeList
Notification
Number
Object
OfflineAudioCompletionEvent
OfflineAudioContext
OffscreenCanvas
Option
OscillatorNode
PageTransitionEvent
PannerNode
Path2D
PaymentAddress
PaymentRequest
PaymentRequestUpdateEvent
PaymentResponse
Performance
PerformanceEntry
PerformanceLongTaskTiming
PerformanceMark
PerformanceMeasure
PerformanceNavigation
PerformanceNavigationTiming
PerformanceObserver
PerformanceObserverEntryList
PerformancePaintTiming
PerformanceResourceTiming
PerformanceTiming
PeriodicWave
PermissionStatus
Permissions
PhotoCapabilities
Plugin
PluginArray
PointerEvent
PopStateEvent
Presentation
PresentationAvailability
PresentationConnection
PresentationConnectionAvailableEvent
PresentationConnectionCloseEvent
PresentationConnectionList
PresentationReceiver
PresentationRequest
ProcessingInstruction
ProgressEvent
Promise
PromiseRejectionEvent
Proxy
PushManager
PushSubscription
PushSubscriptionOptions
RTCCertificate
RTCDataChannel
RTCDataChannelEvent
RTCDtlsTransport
RTCIceCandidate
RTCIceGatherer
RTCIceTransport
RTCPeerConnection
RTCPeerConnectionIceEvent
RTCRtpContributingSource
RTCRtpReceiver
RTCRtpSender
RTCSctpTransport
RTCSessionDescription
RTCStatsReport
RTCTrackEvent
RadioNodeList
Range
RangeError
React
ReadableStream
ReferenceError
Reflect
RegExp
RemotePlayback
Request
ResizeObserver
ResizeObserverEntry
Response
SVGAElement
SVGAngle
SVGAnimateElement
SVGAnimateMotionElement
SVGAnimateTransformElement
SVGAnimatedAngle
SVGAnimatedBoolean
SVGAnimatedEnumeration
SVGAnimatedInteger
SVGAnimatedLength
SVGAnimatedLengthList
SVGAnimatedNumber
SVGAnimatedNumberList
SVGAnimatedPreserveAspectRatio
SVGAnimatedRect
SVGAnimatedString
SVGAnimatedTransformList
SVGAnimationElement
SVGCircleElement
SVGClipPathElement
SVGComponentTransferFunctionElement
SVGDefsElement
SVGDescElement
SVGDiscardElement
SVGElement
SVGEllipseElement
SVGFEBlendElement
SVGFEColorMatrixElement
SVGFEComponentTransferElement
SVGFECompositeElement
SVGFEConvolveMatrixElement
SVGFEDiffuseLightingElement
SVGFEDisplacementMapElement
SVGFEDistantLightElement
SVGFEDropShadowElement
SVGFEFloodElement
SVGFEFuncAElement
SVGFEFuncBElement
SVGFEFuncGElement
SVGFEFuncRElement
SVGFEGaussianBlurElement
SVGFEImageElement
SVGFEMergeElement
SVGFEMergeNodeElement
SVGFEMorphologyElement
SVGFEOffsetElement
SVGFEPointLightElement
SVGFESpecularLightingElement
SVGFESpotLightElement
SVGFETileElement
SVGFETurbulenceElement
SVGFilterElement
SVGForeignObjectElement
SVGGElement
SVGGeometryElement
SVGGradientElement
SVGGraphicsElement
SVGImageElement
SVGLength
SVGLengthList
SVGLineElement
SVGLinearGradientElement
SVGMPathElement
SVGMarkerElement
SVGMaskElement
SVGMatrix
SVGMetadataElement
SVGNumber
SVGNumberList
SVGPathElement
SVGPatternElement
SVGPoint
SVGPointList
SVGPolygonElement
SVGPolylineElement
SVGPreserveAspectRatio
SVGRadialGradientElement
SVGRect
SVGRectElement
SVGSVGElement
SVGScriptElement
SVGSetElement
SVGStopElement
SVGStringList
SVGStyleElement
SVGSwitchElement
SVGSymbolElement
SVGTSpanElement
SVGTextContentElement
SVGTextElement
SVGTextPathElement
SVGTextPositioningElement
SVGTitleElement
SVGTransform
SVGTransformList
SVGUnitTypes
SVGUseElement
SVGViewElement
Screen
ScreenOrientation
ScriptProcessorNode
SecurityPolicyViolationEvent
Selection
ServiceWorker
ServiceWorkerContainer
ServiceWorkerRegistration
Set
ShadowRoot
SharedArrayBuffer
SharedWorker
SourceBuffer
SourceBufferList
SpeechSynthesisEvent
SpeechSynthesisUtterance
StaticRange
StereoPannerNode
Storage
StorageEvent
StorageManager
String
StyleSheet
StyleSheetList
SubtleCrypto
Symbol
SyntaxError
TaskAttributionTiming
Text
TextDecoder
TextEncoder
TextEvent
TextMetrics
TextTrack
TextTrackCue
TextTrackCueList
TextTrackList
TimeRanges
Touch
TouchEvent
TouchList
TrackEvent
TransitionEvent
TreeWalker
TypeError
UIEvent
URIError
URL
URLSearchParams
Uint16Array
Uint32Array
Uint8Array
Uint8ClampedArray
VTTCue
ValidityState
VisualViewport
WaveShaperNode
WeakMap
WeakSet
WebAssembly
WebGL2RenderingContext
WebGLActiveInfo
WebGLBuffer
WebGLContextEvent
WebGLFramebuffer
WebGLProgram
WebGLQuery
WebGLRenderbuffer
WebGLRenderingContext
WebGLSampler
WebGLShader
WebGLShaderPrecisionFormat
WebGLSync
WebGLTexture
WebGLTransformFeedback
WebGLUniformLocation
WebGLVertexArrayObject
WebSocket
WheelEvent
Window
Worker
WritableStream
XMLDocument
XMLHttpRequest
XMLHttpRequestEventTarget
XMLHttpRequestUpload
XMLSerializer
XPathEvaluator
XPathExpression
XPathResult
XSLTProcessor
_defineProperty
_extends
_toConsumableArray
abstract

View File

@ -1,7 +1,7 @@
use crate::{
class::Class,
function::Function,
ident::Ident,
ident::{Ident, PrivateName},
jsx::{JSXElement, JSXEmptyExpr, JSXFragment, JSXMemberExpr, JSXNamespacedName},
lit::{Lit, Str},
operators::{AssignOp, BinaryOp, UnaryOp, UpdateOp},
@ -89,6 +89,8 @@ pub enum Expr {
TsNonNull(TsNonNullExpr),
TsTypeCast(TsTypeCastExpr),
TsAs(TsAsExpr),
PrivateName(PrivateName),
}
#[ast_node]

View File

@ -375,6 +375,7 @@ impl<'a> Emitter<'a> {
Expr::Unary(ref n) => emit!(n),
Expr::Update(ref n) => emit!(n),
Expr::Yield(ref n) => emit!(n),
Expr::PrivateName(ref n) => emit!(n),
Expr::JSXMebmer(ref n) => emit!(n),
Expr::JSXNamespacedName(ref n) => emit!(n),
@ -685,6 +686,7 @@ impl<'a> Emitter<'a> {
self.wr.increase_indent()?;
emit!(expr);
self.wr.decrease_indent()?;
self.wr.write_line()?;
}
}
}
@ -1329,13 +1331,15 @@ impl<'a> Emitter<'a> {
#[emitter]
pub fn emit_empty_stmt(&mut self, node: &EmptyStmt) -> Result {
punct!(";")
punct!(";");
self.wr.write_line()?;
}
#[emitter]
pub fn emit_debugger_stmt(&mut self, node: &DebuggerStmt) -> Result {
keyword!("debugger");
semi!();
self.wr.write_line()?;
}
#[emitter]

View File

@ -63,16 +63,18 @@ impl<'a, W: Write> JsWriter<'a, W> {
if data.len() > 0 {
if let Some(span) = span {
let loc = self.cm.lookup_char_pos(span.lo());
if !span.is_dummy() {
let loc = self.cm.lookup_char_pos(span.lo());
self.srcmap.add(
self.line_count as _,
self.line_pos as _,
loc.line as _,
loc.col.0 as _,
None,
None,
);
self.srcmap.add(
self.line_count as _,
self.line_pos as _,
loc.line as _,
loc.col.0 as _,
None,
None,
);
}
}
if self.line_start {
@ -82,16 +84,18 @@ impl<'a, W: Write> JsWriter<'a, W> {
cnt += self.raw_write(data.as_bytes())?;
if let Some(span) = span {
let loc = self.cm.lookup_char_pos(span.hi());
if !span.is_dummy() {
let loc = self.cm.lookup_char_pos(span.hi());
self.srcmap.add(
self.line_count as _,
self.line_pos as _,
loc.line as _,
loc.col.0 as _,
None,
None,
);
self.srcmap.add(
self.line_count as _,
self.line_pos as _,
loc.line as _,
loc.col.0 as _,
None,
None,
);
}
}
}

View File

@ -159,6 +159,8 @@ impl StartsWithAlphaNum for Expr {
| Expr::New(_)
| Expr::MetaProp(_) => true,
Expr::PrivateName(_) => false,
// Handle other literals.
Expr::Lit(_) => false,

View File

@ -1 +1,2 @@
(a)=>b;
(a)=>b
;

View File

@ -1 +1,2 @@
(a)=>b;
(a)=>b
;

View File

@ -1 +1,2 @@
(a)=>1;
(a)=>1
;

View File

@ -32,7 +32,11 @@
};
({ a , b , c , d , e })=>{
};
([a])=>b;
([a, b])=>c;
({ a })=>b;
({ a , b })=>c;
([a])=>b
;
([a, b])=>c
;
({ a })=>b
;
({ a , b })=>c
;

View File

@ -1 +1,2 @@
(eval = 1)=>2;
(eval = 1)=>2
;

View File

@ -1 +1,2 @@
((a)=>a);
((a)=>a
);

View File

@ -1 +1,2 @@
(yield)=>1;
(yield)=>1
;

View File

@ -1 +1,2 @@
()=>a = 1;
()=>a = 1
;

View File

@ -1,5 +1,6 @@
class a extends b{
constructor(){
()=>super();
()=>super()
;
}
}

View File

@ -1 +1,2 @@
([])=>1;
([])=>1
;

View File

@ -1 +1,2 @@
([a, ...b])=>1;
([a, ...b])=>1
;

View File

@ -1 +1,2 @@
({ a })=>1;
({ a })=>1
;

View File

@ -1 +1,2 @@
(a)=>'b';
(a)=>'b'
;

View File

@ -1 +1,2 @@
(eval)=>1;
(eval)=>1
;

View File

@ -1 +1,3 @@
(a)=>((b, c)=>( a, b, c));
(a)=>((b, c)=>( a, b, c)
)
;

View File

@ -1,3 +1,4 @@
(a)=>({
b: 1
});
})
;

View File

@ -1 +1,2 @@
(a)=>yield * 1;
(a)=>yield * 1
;

View File

@ -1,2 +1,4 @@
a = (b)=>false;
a = ()=>false;
a = (b)=>false
;
a = ()=>false
;

View File

@ -1 +1,2 @@
()=>()=>1;
()=>()=>1
;

View File

@ -1 +1,2 @@
(...a)=>1;
(...a)=>1
;

View File

@ -1 +1,2 @@
(a)=>a * yield;
(a)=>a * yield
;

View File

@ -1 +1,2 @@
([[[[[[[[[[[[[[[[[[[[{ a =b }]]]]]]]]]]]]]]]]]]]])=>1;
([[[[[[[[[[[[[[[[[[[[{ a =b }]]]]]]]]]]]]]]]]]]]])=>1
;

View File

@ -1 +1,2 @@
(eval)=>'use strict';
(eval)=>'use strict'
;

View File

@ -1 +1,2 @@
({ a , b =b , a: c , [a]: [d] })=>1;
({ a , b =b , a: c , [a]: [d] })=>1
;

View File

@ -1 +1,2 @@
(eval, a = 1)=>2;
(eval, a = 1)=>2
;

View File

@ -1 +1,2 @@
(a, { b =1 })=>2;
(a, { b =1 })=>2
;

View File

@ -1 +1,2 @@
(yield)=>1;
(yield)=>1
;

View File

@ -1 +1,2 @@
([a, , b])=>1;
([a, , b])=>1
;

View File

@ -1 +1,2 @@
()=>'a';
()=>'a'
;

View File

@ -1 +1,2 @@
({})=>1;
({})=>1
;

View File

@ -1,2 +1,3 @@
'use strict';
(a)=>1;
(a)=>1
;

View File

@ -1 +1,2 @@
({ a =1 }, {})=>2;
({ a =1 }, {})=>2
;

View File

@ -1 +1 @@
1.a;
1..a;

View File

@ -1 +1,2 @@
(a, b)=>1 + 2;
(a, b)=>1 + 2
;

View File

@ -1 +1,2 @@
()=>1 + 2;
()=>1 + 2
;

View File

@ -1 +1,2 @@
(arguments)=>1;
(arguments)=>1
;

View File

@ -1 +1,2 @@
(a, b, [c])=>1;
(a, b, [c])=>1
;

View File

@ -1 +1,2 @@
({ a =1 }, { b =2 }, { c =3 })=>4;
({ a =1 }, { b =2 }, { c =3 })=>4
;

View File

@ -1 +1,2 @@
({ a =1 })=>a;
({ a =1 })=>a
;

View File

@ -1,10 +1,18 @@
(a)=>b;
(a, b)=>c;
()=>b;
(a)=>(b)=>c;
(a)=>((b)=>c);
()=>(b, c)=>d;
(a)=>b
;
(a, b)=>c
;
()=>b
;
(a)=>(b)=>c
;
(a)=>((b)=>c
)
;
()=>(b, c)=>d
;
(a)=>{
return b;
};
(a)=>'e';
(a)=>'e'
;

View File

@ -1 +1,2 @@
(a)=>'b';
(a)=>'b'
;

View File

@ -1 +1 @@
1.a;
1..a;

View File

@ -1 +1,2 @@
([a])=>[1];
([a])=>[1]
;

View File

@ -1 +1,2 @@
()=>1, 2;
()=>1
, 2;

View File

@ -1,3 +1,4 @@
function* a() {
()=>yield;
()=>yield
;
}

View File

@ -1 +1,2 @@
(a, b)=>'c';
(a, b)=>'c'
;

View File

@ -1 +1,2 @@
(a)=>(b)=>(c)=>1;
(a)=>(b)=>(c)=>1
;

View File

@ -1 +1,2 @@
(a)=>(b)=>1;
(a)=>(b)=>1
;

View File

@ -1 +1,2 @@
(a, b, ...c)=>1;
(a, b, ...c)=>1
;

View File

@ -1 +1,2 @@
(eval, a)=>1;
(eval, a)=>1
;

View File

@ -1 +1,2 @@
(()=>1);
(()=>1
);

View File

@ -1 +1,2 @@
(a = 1)=>a * a;
(a = 1)=>a * a
;

View File

@ -1,3 +1,4 @@
function* a() {
(b)=>b * yield;
(b)=>b * yield
;
}

View File

@ -1 +1,2 @@
(a)=>0;
(a)=>0
;

View File

@ -1 +1,2 @@
(a, b, ...c)=>1 + 2;
(a, b, ...c)=>1 + 2
;

View File

@ -1 +1,2 @@
([a])=>1;
([a])=>1
;

View File

@ -1 +1,2 @@
(a)=>1;
(a)=>1
;

View File

@ -1 +1,2 @@
()=>1;
()=>1
;

View File

@ -1,5 +1,6 @@
class a{
b() {
()=>super.c;
()=>super.c
;
}
}

View File

@ -1 +1,2 @@
([])=>1;
([])=>1
;

View File

@ -1 +1,2 @@
(()=>null)();
(()=>null
)();

View File

@ -1 +1,2 @@
([a = 1], [])=>2;
([a = 1], [])=>2
;

View File

@ -1 +1,2 @@
([a, b])=>1;
([a, b])=>1
;

View File

@ -787,7 +787,10 @@ impl<'a, I: Input> Parser<'a, I> {
// member expression
// $obj.name
if eat!('.') {
let prop: Box<Expr> = Box::new(self.parse_ident_name().map(Expr::from)?);
let prop: Box<Expr> = Box::new(self.parse_maybe_private_name().map(|e| match e {
Either::Left(p) => Expr::PrivateName(p),
Either::Right(i) => Expr::Ident(i),
})?);
return Ok((
Box::new(Expr::Member(MemberExpr {
span: span!(start),

View File

@ -25,7 +25,7 @@ impl<'a, I: Input> Parser<'a, I> {
syntax_error!(span!(start), SyntaxError::SpaceBetweenHashAndIdent);
}
let id = self.parse_ident(true, true)?;
let id = self.parse_ident_name()?;
Ok(PrivateName {
span: span!(start),
id,

View File

@ -203,6 +203,9 @@ pub(super) trait ExprExt {
Expr::Seq(..) => false,
// MemberExpression is valid assignment target
Expr::PrivateName(..) => false,
// jsx
Expr::JSXMebmer(..)
| Expr::JSXNamespacedName(..)

View File

@ -156,6 +156,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -220,6 +221,7 @@ Module {
),
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,

View File

@ -246,6 +246,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,

View File

@ -71,6 +71,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -135,6 +136,7 @@ Module {
),
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: true,
@ -173,6 +175,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: true,
is_optional: false,
@ -211,6 +214,7 @@ Module {
type_ann: None,
is_static: true,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -249,6 +253,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: Some(
Public
),
@ -289,6 +294,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: Some(
Protected
),
@ -329,6 +335,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: Some(
Private
),
@ -369,6 +376,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: true,
is_optional: false,
@ -407,6 +415,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: true,
is_optional: false,
@ -445,6 +454,7 @@ Module {
type_ann: None,
is_static: true,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -483,6 +493,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: Some(
Public
),
@ -523,6 +534,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: Some(
Public
),
@ -563,6 +575,7 @@ Module {
type_ann: None,
is_static: true,
decorators: [],
computed: false,
accessibility: Some(
Public
),
@ -603,6 +616,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: Some(
Public
),
@ -643,6 +657,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: Some(
Public
),
@ -683,6 +698,7 @@ Module {
type_ann: None,
is_static: true,
decorators: [],
computed: false,
accessibility: Some(
Public
),

View File

@ -71,6 +71,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -109,6 +110,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: true,
@ -173,6 +175,7 @@ Module {
),
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -254,6 +257,7 @@ Module {
),
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -292,6 +296,7 @@ Module {
type_ann: None,
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -356,6 +361,7 @@ Module {
),
is_static: false,
decorators: [],
computed: false,
accessibility: None,
is_abstract: false,
is_optional: false,

View File

@ -129,6 +129,7 @@ Module {
),
is_static: false,
decorators: [],
computed: true,
accessibility: None,
is_abstract: false,
is_optional: false,
@ -225,6 +226,7 @@ Module {
),
is_static: false,
decorators: [],
computed: true,
accessibility: None,
is_abstract: false,
is_optional: true,

View File

@ -1,513 +1,21 @@
use crate::scope::{Scope, ScopeKind};
use crate::pass::Pass;
use ast::*;
use swc_atoms::JsWord;
use swc_common::{Fold, FoldWith, Mark};
use swc_common::{Fold, FoldWith};
pub fn block_scoping() -> BlockFolder<'static> {
BlockFolder::new(Mark::fresh(Mark::root()), Scope::new(ScopeKind::Fn, None))
}
#[derive(Clone)]
pub struct BlockFolder<'a> {
mark: Mark,
current: Scope<'a>,
}
impl<'a> BlockFolder<'a> {
fn new(mark: Mark, current: Scope<'a>) -> Self {
BlockFolder { mark, current }
}
fn mark_for(&self, sym: &JsWord) -> Option<Mark> {
let mut mark = self.mark;
let mut scope = Some(&self.current);
while let Some(cur) = scope {
if cur.declared_symbols.contains_key(sym) {
return Some(mark);
}
mark = mark.parent();
scope = cur.parent;
}
None
}
pub fn block_scoping() -> impl Pass + Clone + Copy {
BlockScoping
}
impl<'a> Fold<Function> for BlockFolder<'a> {
fn fold(&mut self, f: Function) -> Function {
let child_mark = Mark::fresh(self.mark);
#[derive(Clone, Copy)]
struct BlockScoping;
let mut child_folder =
BlockFolder::new(child_mark, Scope::new(ScopeKind::Fn, Some(&self.current)));
f.fold_children(&mut child_folder)
}
}
impl<'a> Fold<BlockStmt> for BlockFolder<'a> {
fn fold(&mut self, block: BlockStmt) -> BlockStmt {
let child_mark = Mark::fresh(self.mark);
let mut child_folder = BlockFolder::new(
child_mark,
Scope::new(ScopeKind::Block, Some(&self.current)),
);
block.fold_children(&mut child_folder)
}
}
impl<'a> Fold<VarDecl> for BlockFolder<'a> {
impl Fold<VarDecl> for BlockScoping {
fn fold(&mut self, var: VarDecl) -> VarDecl {
let var = var.fold_children(self);
VarDecl {
kind: VarDeclKind::Var,
..var
}
}
}
impl<'a> Fold<Pat> for BlockFolder<'a> {
fn fold(&mut self, pat: Pat) -> Pat {
match pat {
Pat::Ident(ident) => {
self.current
.declared_symbols
.insert(ident.sym.clone(), ident.span.ctxt());
let ident = Ident {
span: ident.span.apply_mark(self.mark),
sym: ident.sym,
..ident
};
return Pat::Ident(ident);
}
// TODO(kdy1): Is this ok?
_ => pat.fold_children(self),
}
}
}
impl<'a> Fold<Expr> for BlockFolder<'a> {
fn fold(&mut self, expr: Expr) -> Expr {
match expr {
// Leftmost one of a member expression shoukld be resolved.
Expr::Member(me) => Expr::Member(MemberExpr {
obj: me.obj.fold_with(self),
..me
}),
_ => expr.fold_children(self),
}
}
}
impl<'a> Fold<VarDeclarator> for BlockFolder<'a> {
fn fold(&mut self, decl: VarDeclarator) -> VarDeclarator {
VarDeclarator {
// order is important
init: decl.init.fold_children(self),
name: decl.name.fold_with(self),
..decl
}
}
}
impl<'a> Fold<Ident> for BlockFolder<'a> {
fn fold(&mut self, i: Ident) -> Ident {
let Ident { span, sym, .. } = i;
if let Some(mark) = self.mark_for(&sym) {
Ident {
sym,
span: span.apply_mark(mark),
..i
}
} else {
// Cannot resolve reference. (TODO: Report error)
Ident { sym, span, ..i }
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use swc_common::SyntaxContext;
#[test]
fn test_mark_for() {
::testing::run_test(false, |_, _| {
let mark1 = Mark::fresh(Mark::root());
let mark2 = Mark::fresh(mark1);
let mark3 = Mark::fresh(mark2);
let mark4 = Mark::fresh(mark3);
let folder1 = BlockFolder::new(mark1, Scope::new(ScopeKind::Block, None));
let mut folder2 =
BlockFolder::new(mark2, Scope::new(ScopeKind::Block, Some(&folder1.current)));
folder2
.current
.declared_symbols
.insert("foo".into(), SyntaxContext::empty());
let mut folder3 =
BlockFolder::new(mark3, Scope::new(ScopeKind::Block, Some(&folder2.current)));
folder3
.current
.declared_symbols
.insert("bar".into(), SyntaxContext::empty());
assert_eq!(folder3.mark_for(&"bar".into()), Some(mark3));
let mut folder4 =
BlockFolder::new(mark4, Scope::new(ScopeKind::Block, Some(&folder3.current)));
folder4
.current
.declared_symbols
.insert("foo".into(), SyntaxContext::empty());
assert_eq!(folder4.mark_for(&"foo".into()), Some(mark4));
assert_eq!(folder4.mark_for(&"bar".into()), Some(mark3));
Ok(())
})
.unwrap();
}
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
basic,
r#"
{
var foo = 1;
{
let foo = 2;
use(foo);
}
use(foo)
}
"#,
r#"
{
var foo = 1;
{
var foo1 = 2;
use(foo1);
}
use(foo);
}
"#
);
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
general_assignment_patterns,
r#"const foo = "foo";
function foobar() {
for (let item of [1, 2, 3]) {
let foo = "bar";
[bar, foo] = [1, 2];
}
}"#,
r#"var foo = "foo";
function foobar() {
for (var item of [1, 2, 3]) {
var foo1 = "bar";
[bar, foo1] = [1, 2];
}
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
general_function,
r#"function test() {
let foo = "bar";
}"#,
r#"function test() {
var foo = "bar";
}"#
);
test!(
ignore,
::swc_ecma_parser::Syntax::default(),
block_scoping(),
babel_issue_1051,
r#"foo.func1 = function() {
if (cond1) {
for (;;) {
if (cond2) {
function func2() {}
function func3() {}
func4(function() {
func2();
});
break;
}
}
}
};"#,
r#"foo.func1 = function () {
if (cond1) {
for (;;) {
if (cond2) {
var _ret = function () {
function func2() {}
function func3() {}
func4(function () {
func2();
});
return "break";
}();
if (_ret === "break") break;
}
}
}
};"#
);
test!(
ignore,
::swc_ecma_parser::Syntax::default(),
// TODO(kdy1): WTF is this (again)?
block_scoping(),
babel_issue_2174,
r#"if (true) {
function foo() {}
function bar() {
return foo;
}
for (var x in {}) {}
}"#,
r#"
if (true) {
var foo = function () {};
var bar = function () {
return foo;
};
for (var x in {}) {}
}"#
);
test!(
ignore,
::swc_ecma_parser::Syntax::default(),
block_scoping(),
babel_issue_4363,
r#"function WithoutCurlyBraces() {
if (true)
for (let k in kv) {
function foo() { return this }
function bar() { return foo.call(this) }
console.log(this, k) // => undefined
}
}
function WithCurlyBraces() {
if (true) {
for (let k in kv) {
function foo() { return this }
function bar() { return foo.call(this) }
console.log(this, k) // => 777
}
}
}"#,
r#"function WithoutCurlyBraces() {
var _this = this;
if (true) {
var _loop = function (k) {
function foo() {
return this;
}
function bar() {
return foo.call(this);
}
console.log(_this, k); // => undefined
};
for (var k in kv) {
_loop(k);
}
}
}
function WithCurlyBraces() {
var _this2 = this;
if (true) {
var _loop2 = function (k) {
function foo() {
return this;
}
function bar() {
return foo.call(this);
}
console.log(_this2, k); // => 777
};
for (var k in kv) {
_loop2(k);
}
}
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
babel_issue_4946,
r#"(function foo() {
let foo = true;
});"#,
r#"(function foo() {
var foo = true;
});"#
);
// TODO: try {} catch (a) { let a } should report error
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
babel_issue_973,
r#"let arr = [];
for(let i = 0; i < 10; i++) {
for (let i = 0; i < 10; i++) {
arr.push(() => i);
}
}
"#,
r#"var arr = [];
for(var i = 0; i < 10; i++){
for(var i1 = 0; i1 < 10; i1++){
arr.push(()=>i1);
}
}"#
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
pass_assignment,
r#"let a = 1;
a = 2;
expect(a).toBe(2);"#
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
pass_call,
r#"let a = 1;
function b() {
return a + 1;
}
expect(b()).toBe(2);"#
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
pass_update,
r#"let a = 1;
a++;
expect(a).toBe(2);"#
);
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
fn_param,
r#"let a = 'foo';
function foo(a) {
use(a);
}"#,
r#"var a = 'foo';
function foo(a1) {
use(a1);
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
fn_body,
r#"let a = 'foo';
function foo() {
let a = 'bar';
use(a);
}"#,
r#"var a = 'foo';
function foo() {
var a1 = 'bar';
use(a1);
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
shorthand,
r#"let a = 'foo';
function foo() {
let a = 'bar';
use({a});
}"#,
r#"var a = 'foo';
function foo() {
var a1 = 'bar';
use({a: a1});
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
same_level,
r#"
var a = 'foo';
var a = 'bar';
"#,
r#"
var a = 'foo';
var a = 'bar';
"#
);
test!(
::swc_ecma_parser::Syntax::default(),
block_scoping(),
class_block,
r#"
var Foo = function(_Bar) {
_inherits(Foo, _Bar);
function Foo() {
}
return Foo;
}(Bar);
"#,
r#"
var Foo = function(_Bar) {
_inherits(Foo, _Bar);
function Foo() {
}
return Foo;
}(Bar);
"#
);
}

View File

@ -2,6 +2,7 @@ use super::get_prototype_of;
use crate::{helpers::Helpers, util::ExprFactory};
use ast::*;
use std::iter;
use swc_atoms::JsWord;
use swc_common::{Fold, FoldWith, Mark, Visit, VisitWith, DUMMY_SP};
pub(super) struct SuperCallFinder {
@ -236,6 +237,9 @@ macro_rules! ignore_return {
ignore_return!(Function);
ignore_return!(Class);
ignore_return!(ArrowExpr);
ignore_return!(Constructor);
fold_only_key!(ConstructorFolder);
impl<'a> Fold<Expr> for ConstructorFolder<'a> {
fn fold(&mut self, expr: Expr) -> Expr {
@ -394,6 +398,12 @@ pub(super) fn replace_this_in_constructor(mark: Mark, c: Constructor) -> (Constr
wrap_with_assertiion: bool,
}
impl Fold<Class> for Replacer {
fn fold(&mut self, n: Class) -> Class {
n
}
}
impl Fold<Expr> for Replacer {
fn fold(&mut self, expr: Expr) -> Expr {
match expr {
@ -455,3 +465,45 @@ pub(super) fn replace_this_in_constructor(mark: Mark, c: Constructor) -> (Constr
(c, v.found)
}
/// # In
///
/// ```js
///
/// class Example {
/// constructor() {
/// var Example;
/// }
/// }
/// ```
///
/// # Out
///
/// ```js
/// var Example = function Example() {
/// _classCallCheck(this, Example);
/// var Example1;
/// };
/// ```
pub(super) struct VarRenamer<'a> {
pub mark: Mark,
pub class_name: &'a JsWord,
}
impl<'a> Fold<Pat> for VarRenamer<'a> {
fn fold(&mut self, pat: Pat) -> Pat {
match pat {
Pat::Ident(ident) => {
if *self.class_name == ident.sym {
return Pat::Ident(Ident {
span: ident.span.apply_mark(self.mark),
..ident
});
} else {
Pat::Ident(ident)
}
}
_ => pat.fold_children(self),
}
}
}

View File

@ -0,0 +1,27 @@
macro_rules! fold_only_key {
($T:tt) => {
impl<'a> Fold<ClassMember> for $T<'a> {
fn fold(&mut self, m: ClassMember) -> ClassMember {
match m {
ClassMember::Method(m) => ClassMember::Method(Method {
key: m.key.fold_with(self),
..m
}),
ClassMember::PrivateMethod(m) => ClassMember::PrivateMethod(PrivateMethod {
key: m.key.fold_with(self),
..m
}),
ClassMember::ClassProp(p) => ClassMember::ClassProp(ClassProp {
key: p.key.fold_with(self),
..p
}),
ClassMember::PrivateProp(p) => ClassMember::PrivateProp(PrivateProp {
key: p.key.fold_with(self),
..p
}),
_ => m,
}
}
}
};
}

View File

@ -1,16 +1,17 @@
use self::{
constructor::{
constructor_fn, make_possible_return_value, replace_this_in_constructor, ConstructorFolder,
ReturningMode, SuperCallFinder, SuperFoldingMode,
ReturningMode, SuperCallFinder, SuperFoldingMode, VarRenamer,
},
native::is_native,
prop_name::HashKey,
super_field::SuperFieldAccessFolder,
};
use crate::{
helpers::Helpers,
util::{
alias_ident_for, default_constructor, prop_name_to_expr, ExprFactory, ModuleItemLike,
StmtLike,
alias_ident_for, default_constructor, prepend, prop_name_to_expr, ExprFactory,
ModuleItemLike, StmtLike,
},
};
use ast::*;
@ -18,7 +19,10 @@ use indexmap::IndexMap;
use std::{iter, sync::Arc};
use swc_common::{Fold, FoldWith, Mark, Spanned, Visit, VisitWith, DUMMY_SP};
#[macro_use]
mod macros;
mod constructor;
mod native;
mod prop_name;
mod super_field;
#[cfg(test)]
@ -78,8 +82,6 @@ where
match T::try_into_stmt(stmt) {
Err(node) => match node.try_into_module_decl() {
Ok(decl) => {
let decl = decl.fold_children(self);
match decl {
ModuleDecl::ExportDefaultDecl(ExportDefaultDecl::Class(
ClassExpr { ident, class },
@ -87,6 +89,7 @@ where
let ident = ident.unwrap_or_else(|| quote_ident!("_default"));
let decl = self.fold_class_as_var_decl(ident.clone(), class);
let decl = decl.fold_children(self);
buf.push(T::from_stmt(Stmt::Decl(Decl::Var(decl))));
buf.push(
@ -112,6 +115,7 @@ where
class,
})) => {
let decl = self.fold_class_as_var_decl(ident, class);
let decl = decl.fold_children(self);
buf.push(
match T::try_from_module_decl(ModuleDecl::ExportDecl(
Decl::Var(decl),
@ -121,10 +125,12 @@ where
},
);
}
_ => buf.push(match T::try_from_module_decl(decl) {
Ok(t) => t,
Err(..) => unreachable!(),
}),
_ => {
buf.push(match T::try_from_module_decl(decl.fold_children(self)) {
Ok(t) => t,
Err(..) => unreachable!(),
})
}
};
}
Err(..) => unreachable!(),
@ -221,10 +227,7 @@ impl Classes {
let super_class = class.super_class.clone().unwrap();
let is_super_native = match *super_class {
Expr::Ident(Ident { ref sym, .. }) => match *sym {
js_word!("Object") | js_word!("Array") | js_word!("HTMLElement") => true,
_ => false,
},
Expr::Ident(Ident { ref sym, .. }) => is_native(sym),
_ => false,
};
if is_super_native {
@ -318,11 +321,8 @@ impl Classes {
let mut priv_methods = vec![];
let mut methods = vec![];
let mut prop_init_stmts = vec![];
let mut static_prop_init_stmts = vec![];
let mut constructor = None;
for member in class.body {
let span = member.span();
match member {
ClassMember::Constructor(c) => {
if constructor.is_some() {
@ -333,50 +333,16 @@ impl Classes {
}
ClassMember::PrivateMethod(m) => priv_methods.push(m),
ClassMember::Method(m) => methods.push(m),
ClassMember::ClassProp(ClassProperty {
key,
value: Some(right),
is_static: true,
..
}) => static_prop_init_stmts.push(Stmt::Expr(box Expr::Assign(AssignExpr {
span,
left: PatOrExpr::Expr(box Expr::Member(MemberExpr {
span,
obj: class_name.clone().as_obj(),
computed: match *key {
Expr::Ident(..) => false,
_ => true,
},
prop: key,
})),
op: op!("="),
right,
}))),
ClassMember::ClassProp(ClassProperty {
key,
value: Some(right),
is_static: false,
..
}) => prop_init_stmts.push(Stmt::Expr(box Expr::Assign(AssignExpr {
span,
left: PatOrExpr::Expr(box Expr::Member(MemberExpr {
span,
obj: ThisExpr { span }.as_obj(),
computed: match *key {
Expr::Ident(..) => false,
_ => true,
},
prop: key,
})),
op: op!("="),
right,
}))),
ClassMember::ClassProp(..) => {
unreachable!("classes pass: property\nclass_properties pass should remove this")
}
ClassMember::PrivateProp(..) => unreachable!(
"classes pass: private property\nclass_properties pass should remove this"
),
ClassMember::TsIndexSignature(s) => {
unimplemented!("typescript index signature {:?}", s)
}
ClassMember::PrivateProp(p) => unimplemented!("private class property {:?}", p),
// Skip
_ => {}
}
}
@ -399,15 +365,24 @@ impl Classes {
// Marker for `_this`
let mark = Mark::fresh(Mark::root());
// Process constructor
{
let mut is_constructor_default = false;
let mut constructor = constructor.unwrap_or_else(|| {
is_constructor_default = true;
let mut c = default_constructor(super_class_ident.is_some());
c.params = vec![];
c
// Process constructor
let mut constructor =
constructor.unwrap_or_else(|| default_constructor(super_class_ident.is_some()));
// Rename variables to avoid conflicting with class name
constructor.body = constructor.body.fold_with(&mut VarRenamer {
mark: Mark::fresh(Mark::root()),
class_name: &class_name.sym,
});
// Black magic to detect injected constructor.
let is_constructor_default = constructor.span.is_dummy();
if is_constructor_default {
constructor.params = vec![];
}
let mut insert_this = false;
if super_class_ident.is_some() {
@ -439,6 +414,7 @@ impl Classes {
if super_class_ident.is_some() {
let this = quote_ident!(DUMMY_SP.apply_mark(mark), "_this");
// We should fold body instead of constructor itself.
// Handle `super()`
body = body.fold_with(&mut ConstructorFolder {
is_constructor_default,
@ -502,13 +478,6 @@ impl Classes {
if is_this_declared { Some(mark) } else { None },
);
// TODO: Handle
//
// console.log('foo');
// super();
// console.log('bar');
//
//
stmts.push(Stmt::Decl(Decl::Fn(FnDecl {
ident: class_name.clone(),
function: constructor_fn(Constructor {
@ -520,9 +489,6 @@ impl Classes {
}),
declare: false,
})));
// Handle static properties
stmts.append(&mut static_prop_init_stmts);
}
// convert class methods
@ -561,6 +527,7 @@ impl Classes {
is_static: false,
folding_constructor: true,
in_nested_scope: false,
in_injected_define_property_call: false,
this_alias_mark: None,
};
@ -575,7 +542,7 @@ impl Classes {
kind: VarDeclKind::Var,
decls: vec![VarDeclarator {
span: DUMMY_SP,
name: Pat::Ident(quote_ident!(DUMMY_SP.apply_mark(mark), "_this2")),
name: Pat::Ident(quote_ident!(DUMMY_SP.apply_mark(mark), "_this")),
init: Some(box Expr::This(ThisExpr { span: DUMMY_SP })),
definite: false,
}],
@ -704,6 +671,7 @@ impl Classes {
is_static: m.is_static,
folding_constructor: false,
in_nested_scope: false,
in_injected_define_property_call: false,
this_alias_mark: None,
};
let mut function = m.function.fold_with(&mut folder);
@ -717,7 +685,7 @@ impl Classes {
kind: VarDeclKind::Var,
decls: vec![VarDeclarator {
span: DUMMY_SP,
name: Pat::Ident(quote_ident!(DUMMY_SP.apply_mark(mark), "_this2")),
name: Pat::Ident(quote_ident!(DUMMY_SP.apply_mark(mark), "_this")),
init: Some(box Expr::This(ThisExpr { span: DUMMY_SP })),
definite: false,
}],
@ -797,19 +765,6 @@ fn get_prototype_of(helpers: &Helpers, obj: &Expr) -> Expr {
})
}
/// inject `stmt` after directives
fn prepend(stmts: &mut Vec<Stmt>, stmt: Stmt) {
let idx = stmts
.iter()
.position(|item| match item {
Stmt::Expr(box Expr::Lit(Lit::Str(..))) => false,
_ => true,
})
.unwrap_or(0);
stmts.insert(idx, stmt);
}
fn inject_class_call_check(c: &mut Constructor, name: Ident) {
let class_call_check = Stmt::Expr(box Expr::Call(CallExpr {
span: DUMMY_SP,

View File

@ -0,0 +1,581 @@
use swc_atoms::{js_word, JsWord};
macro_rules! native {
(
$sym:expr,
$(
$i:tt
),*
) => {
match $sym{
$(
js_word!($i) => true,
)*
_ => false
}
};
}
pub(super) fn is_native(sym: &JsWord) -> bool {
native!(
sym,
"Array",
"ArrayBuffer",
"Atomics",
"BigInt",
"BigInt64Array",
"BigUint64Array",
"Boolean",
"DataView",
"Date",
"Error",
"EvalError",
"Float32Array",
"Float64Array",
"Function",
"Infinity",
"Int16Array",
"Int32Array",
"Int8Array",
"JSON",
"Map",
"Math",
"NaN",
"Number",
"Object",
"Promise",
"Proxy",
"RangeError",
"ReferenceError",
"Reflect",
"RegExp",
"Set",
"SharedArrayBuffer",
"String",
"Symbol",
"SyntaxError",
"TypeError",
"Uint16Array",
"Uint32Array",
"Uint8Array",
"Uint8ClampedArray",
"URIError",
"WeakMap",
"WeakSet",
"AbortController",
"AbortSignal",
"AnalyserNode",
"Animation",
"AnimationEffectReadOnly",
"AnimationEffectTiming",
"AnimationEffectTimingReadOnly",
"AnimationEvent",
"AnimationPlaybackEvent",
"AnimationTimeline",
"ApplicationCache",
"ApplicationCacheErrorEvent",
"Attr",
"Audio",
"AudioBuffer",
"AudioBufferSourceNode",
"AudioContext",
"AudioDestinationNode",
"AudioListener",
"AudioNode",
"AudioParam",
"AudioProcessingEvent",
"AudioScheduledSourceNode",
"AudioWorkletGlobalScope",
"AudioWorkletNode",
"AudioWorkletProcessor",
"BarProp",
"BaseAudioContext",
"BatteryManager",
"BeforeUnloadEvent",
"BiquadFilterNode",
"Blob",
"BlobEvent",
"BroadcastChannel",
"BudgetService",
"ByteLengthQueuingStrategy",
"Cache",
"CacheStorage",
"CanvasCaptureMediaStreamTrack",
"CanvasGradient",
"CanvasPattern",
"CanvasRenderingContext2D",
"ChannelMergerNode",
"ChannelSplitterNode",
"CharacterData",
"ClipboardEvent",
"CloseEvent",
"Comment",
"CompositionEvent",
"ConstantSourceNode",
"ConvolverNode",
"CountQueuingStrategy",
"Credential",
"CredentialsContainer",
"Crypto",
"CryptoKey",
"CSS",
"CSSConditionRule",
"CSSFontFaceRule",
"CSSGroupingRule",
"CSSImportRule",
"CSSKeyframeRule",
"CSSKeyframesRule",
"CSSMediaRule",
"CSSNamespaceRule",
"CSSPageRule",
"CSSRule",
"CSSRuleList",
"CSSStyleDeclaration",
"CSSStyleRule",
"CSSStyleSheet",
"CSSSupportsRule",
"CustomElementRegistry",
"CustomEvent",
"DataTransfer",
"DataTransferItem",
"DataTransferItemList",
"DelayNode",
"DeviceMotionEvent",
"DeviceOrientationEvent",
"Document",
"DocumentFragment",
"DocumentType",
"DOMError",
"DOMException",
"DOMImplementation",
"DOMMatrix",
"DOMMatrixReadOnly",
"DOMParser",
"DOMPoint",
"DOMPointReadOnly",
"DOMQuad",
"DOMRect",
"DOMRectReadOnly",
"DOMStringList",
"DOMStringMap",
"DOMTokenList",
"DragEvent",
"DynamicsCompressorNode",
"Element",
"ErrorEvent",
"Event",
"EventSource",
"EventTarget",
"File",
"FileList",
"FileReader",
"FocusEvent",
"FontFace",
"FontFaceSetLoadEvent",
"FormData",
"GainNode",
"Gamepad",
"GamepadButton",
"GamepadEvent",
"HashChangeEvent",
"Headers",
"History",
"HTMLAllCollection",
"HTMLAnchorElement",
"HTMLAreaElement",
"HTMLAudioElement",
"HTMLBaseElement",
"HTMLBodyElement",
"HTMLBRElement",
"HTMLButtonElement",
"HTMLCanvasElement",
"HTMLCollection",
"HTMLContentElement",
"HTMLDataElement",
"HTMLDataListElement",
"HTMLDetailsElement",
"HTMLDialogElement",
"HTMLDirectoryElement",
"HTMLDivElement",
"HTMLDListElement",
"HTMLDocument",
"HTMLElement",
"HTMLEmbedElement",
"HTMLFieldSetElement",
"HTMLFontElement",
"HTMLFormControlsCollection",
"HTMLFormElement",
"HTMLFrameElement",
"HTMLFrameSetElement",
"HTMLHeadElement",
"HTMLHeadingElement",
"HTMLHRElement",
"HTMLHtmlElement",
"HTMLIFrameElement",
"HTMLImageElement",
"HTMLInputElement",
"HTMLLabelElement",
"HTMLLegendElement",
"HTMLLIElement",
"HTMLLinkElement",
"HTMLMapElement",
"HTMLMarqueeElement",
"HTMLMediaElement",
"HTMLMenuElement",
"HTMLMetaElement",
"HTMLMeterElement",
"HTMLModElement",
"HTMLObjectElement",
"HTMLOListElement",
"HTMLOptGroupElement",
"HTMLOptionElement",
"HTMLOptionsCollection",
"HTMLOutputElement",
"HTMLParagraphElement",
"HTMLParamElement",
"HTMLPictureElement",
"HTMLPreElement",
"HTMLProgressElement",
"HTMLQuoteElement",
"HTMLScriptElement",
"HTMLSelectElement",
"HTMLShadowElement",
"HTMLSlotElement",
"HTMLSourceElement",
"HTMLSpanElement",
"HTMLStyleElement",
"HTMLTableCaptionElement",
"HTMLTableCellElement",
"HTMLTableColElement",
"HTMLTableElement",
"HTMLTableRowElement",
"HTMLTableSectionElement",
"HTMLTemplateElement",
"HTMLTextAreaElement",
"HTMLTimeElement",
"HTMLTitleElement",
"HTMLTrackElement",
"HTMLUListElement",
"HTMLUnknownElement",
"HTMLVideoElement",
"IDBCursor",
"IDBCursorWithValue",
"IDBDatabase",
"IDBFactory",
"IDBIndex",
"IDBKeyRange",
"IDBObjectStore",
"IDBOpenDBRequest",
"IDBRequest",
"IDBTransaction",
"IDBVersionChangeEvent",
"IdleDeadline",
"IIRFilterNode",
"Image",
"ImageBitmap",
"ImageBitmapRenderingContext",
"ImageCapture",
"ImageData",
"InputEvent",
"IntersectionObserver",
"IntersectionObserverEntry",
"Intl",
"KeyboardEvent",
"KeyframeEffect",
"KeyframeEffectReadOnly",
"Location",
"MediaDeviceInfo",
"MediaDevices",
"MediaElementAudioSourceNode",
"MediaEncryptedEvent",
"MediaError",
"MediaKeyMessageEvent",
"MediaKeySession",
"MediaKeyStatusMap",
"MediaKeySystemAccess",
"MediaList",
"MediaQueryList",
"MediaQueryListEvent",
"MediaRecorder",
"MediaSettingsRange",
"MediaSource",
"MediaStream",
"MediaStreamAudioDestinationNode",
"MediaStreamAudioSourceNode",
"MediaStreamEvent",
"MediaStreamTrack",
"MediaStreamTrackEvent",
"MessageChannel",
"MessageEvent",
"MessagePort",
"MIDIAccess",
"MIDIConnectionEvent",
"MIDIInput",
"MIDIInputMap",
"MIDIMessageEvent",
"MIDIOutput",
"MIDIOutputMap",
"MIDIPort",
"MimeType",
"MimeTypeArray",
"MouseEvent",
"MutationEvent",
"MutationObserver",
"MutationRecord",
"NamedNodeMap",
"NavigationPreloadManager",
"Navigator",
"NetworkInformation",
"Node",
"NodeFilter",
"NodeIterator",
"NodeList",
"Notification",
"OfflineAudioCompletionEvent",
"OfflineAudioContext",
"OffscreenCanvas",
"Option",
"OscillatorNode",
"PageTransitionEvent",
"PannerNode",
"Path2D",
"PaymentAddress",
"PaymentRequest",
"PaymentRequestUpdateEvent",
"PaymentResponse",
"Performance",
"PerformanceEntry",
"PerformanceLongTaskTiming",
"PerformanceMark",
"PerformanceMeasure",
"PerformanceNavigation",
"PerformanceNavigationTiming",
"PerformanceObserver",
"PerformanceObserverEntryList",
"PerformancePaintTiming",
"PerformanceResourceTiming",
"PerformanceTiming",
"PeriodicWave",
"Permissions",
"PermissionStatus",
"PhotoCapabilities",
"Plugin",
"PluginArray",
"PointerEvent",
"PopStateEvent",
"Presentation",
"PresentationAvailability",
"PresentationConnection",
"PresentationConnectionAvailableEvent",
"PresentationConnectionCloseEvent",
"PresentationConnectionList",
"PresentationReceiver",
"PresentationRequest",
"ProcessingInstruction",
"ProgressEvent",
"PromiseRejectionEvent",
"PushManager",
"PushSubscription",
"PushSubscriptionOptions",
"RadioNodeList",
"Range",
"ReadableStream",
"RemotePlayback",
"Request",
"ResizeObserver",
"ResizeObserverEntry",
"Response",
"RTCCertificate",
"RTCDataChannel",
"RTCDataChannelEvent",
"RTCDtlsTransport",
"RTCIceCandidate",
"RTCIceGatherer",
"RTCIceTransport",
"RTCPeerConnection",
"RTCPeerConnectionIceEvent",
"RTCRtpContributingSource",
"RTCRtpReceiver",
"RTCRtpSender",
"RTCSctpTransport",
"RTCSessionDescription",
"RTCStatsReport",
"RTCTrackEvent",
"Screen",
"ScreenOrientation",
"ScriptProcessorNode",
"SecurityPolicyViolationEvent",
"Selection",
"ServiceWorker",
"ServiceWorkerContainer",
"ServiceWorkerRegistration",
"ShadowRoot",
"SharedWorker",
"SourceBuffer",
"SourceBufferList",
"SpeechSynthesisEvent",
"SpeechSynthesisUtterance",
"StaticRange",
"StereoPannerNode",
"Storage",
"StorageEvent",
"StorageManager",
"StyleSheet",
"StyleSheetList",
"SubtleCrypto",
"SVGAElement",
"SVGAngle",
"SVGAnimatedAngle",
"SVGAnimatedBoolean",
"SVGAnimatedEnumeration",
"SVGAnimatedInteger",
"SVGAnimatedLength",
"SVGAnimatedLengthList",
"SVGAnimatedNumber",
"SVGAnimatedNumberList",
"SVGAnimatedPreserveAspectRatio",
"SVGAnimatedRect",
"SVGAnimatedString",
"SVGAnimatedTransformList",
"SVGAnimateElement",
"SVGAnimateMotionElement",
"SVGAnimateTransformElement",
"SVGAnimationElement",
"SVGCircleElement",
"SVGClipPathElement",
"SVGComponentTransferFunctionElement",
"SVGDefsElement",
"SVGDescElement",
"SVGDiscardElement",
"SVGElement",
"SVGEllipseElement",
"SVGFEBlendElement",
"SVGFEColorMatrixElement",
"SVGFEComponentTransferElement",
"SVGFECompositeElement",
"SVGFEConvolveMatrixElement",
"SVGFEDiffuseLightingElement",
"SVGFEDisplacementMapElement",
"SVGFEDistantLightElement",
"SVGFEDropShadowElement",
"SVGFEFloodElement",
"SVGFEFuncAElement",
"SVGFEFuncBElement",
"SVGFEFuncGElement",
"SVGFEFuncRElement",
"SVGFEGaussianBlurElement",
"SVGFEImageElement",
"SVGFEMergeElement",
"SVGFEMergeNodeElement",
"SVGFEMorphologyElement",
"SVGFEOffsetElement",
"SVGFEPointLightElement",
"SVGFESpecularLightingElement",
"SVGFESpotLightElement",
"SVGFETileElement",
"SVGFETurbulenceElement",
"SVGFilterElement",
"SVGForeignObjectElement",
"SVGGElement",
"SVGGeometryElement",
"SVGGradientElement",
"SVGGraphicsElement",
"SVGImageElement",
"SVGLength",
"SVGLengthList",
"SVGLinearGradientElement",
"SVGLineElement",
"SVGMarkerElement",
"SVGMaskElement",
"SVGMatrix",
"SVGMetadataElement",
"SVGMPathElement",
"SVGNumber",
"SVGNumberList",
"SVGPathElement",
"SVGPatternElement",
"SVGPoint",
"SVGPointList",
"SVGPolygonElement",
"SVGPolylineElement",
"SVGPreserveAspectRatio",
"SVGRadialGradientElement",
"SVGRect",
"SVGRectElement",
"SVGScriptElement",
"SVGSetElement",
"SVGStopElement",
"SVGStringList",
"SVGStyleElement",
"SVGSVGElement",
"SVGSwitchElement",
"SVGSymbolElement",
"SVGTextContentElement",
"SVGTextElement",
"SVGTextPathElement",
"SVGTextPositioningElement",
"SVGTitleElement",
"SVGTransform",
"SVGTransformList",
"SVGTSpanElement",
"SVGUnitTypes",
"SVGUseElement",
"SVGViewElement",
"TaskAttributionTiming",
"Text",
"TextDecoder",
"TextEncoder",
"TextEvent",
"TextMetrics",
"TextTrack",
"TextTrackCue",
"TextTrackCueList",
"TextTrackList",
"TimeRanges",
"Touch",
"TouchEvent",
"TouchList",
"TrackEvent",
"TransitionEvent",
"TreeWalker",
"UIEvent",
"URL",
"URLSearchParams",
"ValidityState",
"VisualViewport",
"VTTCue",
"WaveShaperNode",
"WebAssembly",
"WebGL2RenderingContext",
"WebGLActiveInfo",
"WebGLBuffer",
"WebGLContextEvent",
"WebGLFramebuffer",
"WebGLProgram",
"WebGLQuery",
"WebGLRenderbuffer",
"WebGLRenderingContext",
"WebGLSampler",
"WebGLShader",
"WebGLShaderPrecisionFormat",
"WebGLSync",
"WebGLTexture",
"WebGLTransformFeedback",
"WebGLUniformLocation",
"WebGLVertexArrayObject",
"WebSocket",
"WheelEvent",
"Window",
"Worker",
"WritableStream",
"XMLDocument",
"XMLHttpRequest",
"XMLHttpRequestEventTarget",
"XMLHttpRequestUpload",
"XMLSerializer",
"XPathEvaluator",
"XPathExpression",
"XPathResult",
"XSLTProcessor"
)
}

View File

@ -5,7 +5,7 @@ use crate::{
};
use ast::*;
use std::iter;
use swc_common::{Fold, FoldWith, Mark, Span, DUMMY_SP};
use swc_common::{Fold, FoldWith, Mark, Span, Spanned, DUMMY_SP};
/// Process function body.
///
@ -30,6 +30,9 @@ pub(super) struct SuperFieldAccessFolder<'a> {
pub folding_constructor: bool,
/// True while folding **injected** `_defineProperty` call
pub in_injected_define_property_call: bool,
/// True while folding a function / class.
pub in_nested_scope: bool,
@ -59,7 +62,8 @@ macro_rules! mark_nested {
($T:tt) => {
impl<'a> Fold<$T> for SuperFieldAccessFolder<'a> {
fn fold(&mut self, n: $T) -> $T {
if self.folding_constructor {
// injected `_defineProperty` should be handled like method
if self.folding_constructor && !self.in_injected_define_property_call {
let old = self.in_nested_scope;
self.in_nested_scope = true;
let n = n.fold_children(self);
@ -76,6 +80,9 @@ macro_rules! mark_nested {
mark_nested!(Function);
mark_nested!(Class);
fold_only_key!(SuperFieldAccessFolder);
fold_only_key!(SuperCalleeFolder);
impl<'a> Fold<Expr> for SuperCalleeFolder<'a> {
fn fold(&mut self, n: Expr) -> Expr {
match n {
@ -86,7 +93,7 @@ impl<'a> Fold<Expr> for SuperCalleeFolder<'a> {
return Expr::Ident(quote_ident!(
span.apply_mark(self.this_alias_mark.unwrap()),
"_this2"
"_this"
));
}
_ => {}
@ -315,7 +322,7 @@ impl<'a> SuperCalleeFolder<'a> {
arg: left,
}),
}
.wrap_with_paren()
.into()
} else {
left
};
@ -378,6 +385,28 @@ impl<'a> SuperCalleeFolder<'a> {
impl<'a> Fold<Expr> for SuperFieldAccessFolder<'a> {
fn fold(&mut self, n: Expr) -> Expr {
// We pretend method folding mode for while folding injected `_defineProperty`
// calls.
if n.span().is_dummy() {
match n {
Expr::Call(CallExpr {
callee:
ExprOrSuper::Expr(box Expr::Ident(Ident {
sym: js_word!("_defineProperty"),
..
})),
..
}) => {
let old = self.in_injected_define_property_call;
self.in_injected_define_property_call = true;
let n = n.fold_children(self);
self.in_injected_define_property_call = old;
return n;
}
_ => {}
}
}
let mut callee_folder = SuperCalleeFolder {
class_name: self.class_name,
inject_get: false,

View File

@ -1,5 +1,5 @@
use super::*;
use crate::compat::es2015::{arrow, block_scoping, Spread};
use crate::compat::es2015::{arrow, block_scoping, resolver, Spread};
use swc_common::{sync::Lrc, FilePathMapping, SourceMap};
use swc_ecma_parser::{EsConfig, Syntax};
@ -18,16 +18,79 @@ fn tr(helpers: Arc<Helpers>) -> impl Fold<Module> {
fn spec_tr(helpers: Arc<Helpers>) -> impl Fold<Module> {
chain!(
resolver(),
Classes {
helpers: helpers.clone()
},
Spread {
helpers: helpers.clone()
},
block_scoping()
block_scoping(),
)
}
test!(
syntax(),
tr(Default::default()),
custom_singleton,
r#"
let singleton;
class Sub extends Foo {
constructor() {
if (singleton) {
return singleton;
}
singleton = super();
}
}
"#,
r#"
let singleton;
let Sub = function(_Foo) {
_inherits(Sub, _Foo);
function Sub() {
var _this;
_classCallCheck(this, Sub);
if (singleton) {
return _possibleConstructorReturn(_this, singleton);
}
singleton = _this = _possibleConstructorReturn(this, _getPrototypeOf(Sub).call(this));
return _possibleConstructorReturn(_this);
}
return Sub;
}(Foo);
"#
);
test_exec!(
syntax(),
tr,
custom_nested,
r#"
class Hello{
constructor(){
return {
toString () {
return 'hello';
}
};
}
}
class Outer extends Hello{
constructor(){
var _ref = super();
class Inner{
constructor(){
this[_ref] = 'hello';
}
}
return new Inner();
}
}
expect(new Outer().hello).toBe('hello');
"#
);
// spec_constructor_only
test!(
syntax(),
@ -3044,7 +3107,7 @@ function (_super) {
}
return TestEmpty;
}((
}(
/*#__PURE__*/
function () {
@ -3054,7 +3117,7 @@ function () {
}
return _class;
}()));
}());
var TestConstructorOnly =
/*#__PURE__*/
@ -3069,7 +3132,7 @@ function (_super) {
}
return TestConstructorOnly;
}((/*#__PURE__*/
}(/*#__PURE__*/
function () {
@ -3078,7 +3141,7 @@ function () {
}
return _class;
}()));
}());
var TestMethodOnly =
/*#__PURE__*/
@ -3093,7 +3156,7 @@ function (_super) {
}
return TestMethodOnly;
}((
}(
/*#__PURE__*/
function () {
@ -3107,7 +3170,7 @@ function () {
value: function method() {}
}]);
return _class;
}()));
}());
var TestConstructorAndMethod =
/*#__PURE__*/
@ -3122,7 +3185,7 @@ function (_super) {
}
return TestConstructorAndMethod;
}((
}(
/*#__PURE__*/
function () {
@ -3136,7 +3199,7 @@ function () {
value: function method() {}
}]);
return _class;
}()));
}());
var TestMultipleMethods =
/*#__PURE__*/
@ -3151,7 +3214,7 @@ function (_super) {
}
return TestMultipleMethods;
}((
}(
/*#__PURE__*/
function () {
@ -3168,7 +3231,7 @@ function () {
value: function m2() {}
}]);
return _class;
}()));
}());
"#);
@ -3225,9 +3288,9 @@ function (_Hello) {
_inherits(Outer, _Hello);
function Outer() {
var _this2 = this;
var _this = this;
var _this;
var _this1;
_classCallCheck(this, Outer);
@ -3239,7 +3302,7 @@ function (_Hello) {
}
_createClass(Inner, [{
key: _this = _possibleConstructorReturn(_this2, _getPrototypeOf(Outer).call(_this2)),
key: _this1 = _possibleConstructorReturn(_this, _getPrototypeOf(Outer).call(_this)),
value: function () {
return 'hello';
}
@ -3247,7 +3310,7 @@ function (_Hello) {
return Inner;
}();
return _possibleConstructorReturn(_this, new Inner());
return _possibleConstructorReturn(_this1, new Inner());
}
return Outer;

View File

@ -118,8 +118,7 @@ impl_for_for_stmt!(ForInStmt);
impl_for_for_stmt!(ForOfStmt);
fn make_ref_ident_for_for_stmt() -> Ident {
let mark = Mark::fresh(Mark::root());
quote_ident!(DUMMY_SP.apply_mark(mark), "ref")
private_ident!("ref")
}
impl Fold<Vec<VarDeclarator>> for Destructuring {
@ -338,8 +337,7 @@ impl Fold<Function> for Destructuring {
match pat {
Pat::Ident(..) => params.push(pat),
Pat::Array(..) | Pat::Object(..) | Pat::Assign(..) => {
let mark = Mark::fresh(Mark::root());
let ref_ident = quote_ident!(span.apply_mark(mark), "ref");
let ref_ident = private_ident!(span, "ref");
params.push(Pat::Ident(ref_ident.clone()));
decls.push(VarDeclarator {
@ -624,8 +622,7 @@ fn make_ref_ident(decls: &mut Vec<VarDeclarator>, init: Option<Box<Expr>>) -> Id
};
let span = init.span();
let mark = Mark::fresh(Mark::root());
let ref_ident = quote_ident!(span.apply_mark(mark), s);
let ref_ident = private_ident!(span, s);
decls.push(VarDeclarator {
span,
@ -678,6 +675,7 @@ fn can_be_null(e: &Expr) -> bool {
Expr::Lit(Lit::Null(..))
| Expr::This(..)
| Expr::Ident(..)
| Expr::PrivateName(..)
| Expr::Member(..)
| Expr::Call(..)
| Expr::New(..)

View File

@ -21,7 +21,7 @@ test!(
[{ a = 1 }] = foo"#,
r#"let a;
var ref, ref1, ref2;
( ref = foo, ( ref1 = ref[0], ref2 = ref1.a, a = ref2 === void 0 ? 1 : ref2, ref1), ref);"#
ref = foo, ref1 = ref[0], ref2 = ref1.a, a = ref2 === void 0 ? 1 : ref2, ref;"#
);
test!(
@ -39,8 +39,8 @@ test!(
array2,
r#"[a, [b], [c]] = ["hello", [", ", "junk"], ["world"]];"#,
r#"var ref, ref1, ref2;
( ref = ['hello', [', ', 'junk'], ['world']], a = ref[0],
( ref1 = ref[1], b = ref1[0], ref1), ( ref2 = ref[2], c = ref2[0], ref2), ref);
ref = ['hello', [', ', 'junk'], ['world']], a = ref[0], ref1 = ref[1],
b = ref1[0], ref2 = ref[2], c = ref2[0], ref;
"#
);
@ -52,7 +52,7 @@ test!(
[x, y] = [1, 2];"#,
r#"var x, y;
var ref;
( ref = [1, 2], x = ref[0], y = ref[1], ref);"#
ref = [1, 2], x = ref[0], y = ref[1], ref;"#
);
test!(::swc_ecma_parser::Syntax::default(),
@ -301,7 +301,7 @@ test!(
babel_issue_5744,
r#"if (true) [a, b] = [b, a];"#,
r#"var ref;
if (true) ( ref = [b, a], a = ref[0], b = ref[1], ref);"#
if (true) ref = [b, a], a = ref[0], b = ref[1], ref;"#
);
test!(
@ -337,7 +337,7 @@ test!(
member_expr,
r#"[foo.foo, foo.bar] = [1, 2];"#,
r#"var ref;
( ref = [1, 2], foo.foo = ref[0], foo.bar = ref[1], ref);"#
ref = [1, 2], foo.foo = ref[0], foo.bar = ref[1], ref;"#
);
test!(

View File

@ -189,43 +189,41 @@ impl Actual {
test: Some(box Expr::Unary(UnaryExpr {
span: DUMMY_SP,
op: op!("!"),
arg: box Expr::Paren(ParenExpr {
span: DUMMY_SP,
expr: box Expr::Member(MemberExpr {
arg: {
let step_expr = box Expr::Assign(AssignExpr {
span: DUMMY_SP,
obj: ExprOrSuper::Expr(box Expr::Assign(AssignExpr {
left: PatOrExpr::Pat(box Pat::Ident(step.clone())),
op: op!("="),
// `_iterator.next()`
right: box Expr::Call(CallExpr {
span: DUMMY_SP,
left: PatOrExpr::Pat(box Pat::Ident(normal_completion_ident.clone())),
op: op!("="),
right: box Expr::Paren(ParenExpr {
// `_iterator.next`
callee: MemberExpr {
span: DUMMY_SP,
expr: box Expr::Assign(AssignExpr {
span: DUMMY_SP,
left: PatOrExpr::Pat(box Pat::Ident(step.clone())),
op: op!("="),
// `_iterator.next()`
right: box Expr::Call(CallExpr {
span: DUMMY_SP,
// `_iterator.next`
callee: MemberExpr {
span: DUMMY_SP,
computed: false,
obj: ExprOrSuper::Expr(box Expr::Ident(
iterator.clone(),
)),
prop: member_expr!(DUMMY_SP, next),
}
.as_callee(),
args: vec![],
type_args: Default::default(),
}),
}),
}),
})),
computed: false,
prop: box Expr::Ident(quote_ident!("done")),
}),
}),
computed: false,
obj: ExprOrSuper::Expr(box Expr::Ident(iterator.clone())),
prop: member_expr!(DUMMY_SP, next),
}
.as_callee(),
args: vec![],
type_args: Default::default(),
}),
});
let iteration_normal_completion = box Expr::Assign(AssignExpr {
span: DUMMY_SP,
left: PatOrExpr::Pat(box Pat::Ident(normal_completion_ident.clone())),
op: op!("="),
right: box Expr::Member(MemberExpr {
span: DUMMY_SP,
obj: step_expr.as_obj(),
computed: false,
prop: box Expr::Ident(quote_ident!("done")),
}),
});
iteration_normal_completion
},
})),
// `_iteratorNormalCompletion = true`

View File

@ -12,12 +12,14 @@ mod tests;
/// var number = function (x) {
/// return x;
/// };
/// var Foo = (class {});
/// ```
/// ## Out
/// ```js
/// var number = function number(x) {
/// return x;
/// }
/// var Foo = (class Foo {});
/// ```
pub fn function_name() -> FnName {
FnName
@ -32,11 +34,14 @@ struct Renamer {
impl Fold<VarDeclarator> for FnName {
fn fold(&mut self, decl: VarDeclarator) -> VarDeclarator {
let mut decl = decl.fold_children(self);
match decl.name {
Pat::Ident(ref ident) => {
let init = decl.init.fold_with(&mut Renamer {
Pat::Ident(ref mut ident) => {
let mut folder = Renamer {
name: Some(ident.clone()),
});
};
let init = decl.init.fold_with(&mut folder);
return VarDeclarator { init, ..decl };
}
@ -47,18 +52,20 @@ impl Fold<VarDeclarator> for FnName {
impl Fold<AssignExpr> for FnName {
fn fold(&mut self, expr: AssignExpr) -> AssignExpr {
let expr = expr.fold_children(self);
let mut expr = expr.fold_children(self);
if expr.op != op!("=") {
return expr;
}
match expr.left {
PatOrExpr::Pat(box Pat::Ident(ref ident))
| PatOrExpr::Expr(box Expr::Ident(ref ident)) => {
let right = expr.right.fold_with(&mut Renamer {
PatOrExpr::Pat(box Pat::Ident(ref mut ident))
| PatOrExpr::Expr(box Expr::Ident(ref mut ident)) => {
let mut folder = Renamer {
name: Some(ident.clone()),
});
};
let right = expr.right.fold_with(&mut folder);
return AssignExpr { right, ..expr };
}
@ -67,27 +74,36 @@ impl Fold<AssignExpr> for FnName {
}
}
impl Fold<FnExpr> for Renamer {
fn fold(&mut self, expr: FnExpr) -> FnExpr {
match expr.ident {
Some(..) => return expr,
None => FnExpr {
ident: self.name.take(),
..expr
},
macro_rules! impl_for {
($T:tt) => {
impl Fold<$T> for Renamer {
fn fold(&mut self, node: $T) -> $T {
match node.ident {
Some(..) => return node,
None => $T {
ident: self.name.take(),
..node
},
}
}
}
}
};
}
impl_for!(FnExpr);
impl_for!(ClassExpr);
macro_rules! noop {
($T:tt) => {
impl Fold<$T> for Renamer {
/// Don't recurse.
fn fold(&mut self, node: $T) -> $T {
node
}
}
};
}
impl Fold<ObjectLit> for Renamer {
/// Don't recurse.
fn fold(&mut self, node: ObjectLit) -> ObjectLit {
node
}
}
impl Fold<ArrayLit> for Renamer {
/// Don't recurse.
fn fold(&mut self, node: ArrayLit) -> ArrayLit {
node
}
}
noop!(ObjectLit);
noop!(ArrayLit);
noop!(CallExpr);
noop!(NewExpr);

View File

@ -1,8 +1,17 @@
use super::*;
use crate::{
compat::es2015::{block_scoping, resolver},
helpers::Helpers,
};
use std::sync::Arc;
fn tr(_helpers: Arc<Helpers>) -> impl Fold<Module> {
chain!(resolver(), function_name(), block_scoping())
}
test!(
::swc_ecma_parser::Syntax::default(),
FnName,
tr(Default::default()),
basic,
r#"var number = function (x) {
return x;
@ -14,7 +23,7 @@ test!(
test!(
::swc_ecma_parser::Syntax::default(),
FnName,
tr(Default::default()),
assign,
r#"number = function (x) {
return x;
@ -26,7 +35,7 @@ test!(
test!(
::swc_ecma_parser::Syntax::default(),
FnName,
tr(Default::default()),
let_complex,
r#"
let TestClass = {
@ -41,7 +50,7 @@ let TestClass = {
};
"#,
r#"
let TestClass = {
var TestClass = {
name: "John Doe",
testMethodFailure() {
@ -53,3 +62,33 @@ let TestClass = {
}
"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(Default::default()),
class_simple,
r#"
var Foo = function() {
var Foo = function () {
_classCallCheck(this, Foo);
};
_defineProperty(Foo, 'num', 0);
return Foo;
}();
expect(Foo.num).toBe(0);
expect(Foo.num = 1).toBe(1);
expect(Foo.name).toBe('Foo');
"#,
r#"
var Foo = function() {
var Foo = function Foo() {
_classCallCheck(this, Foo);
};
_defineProperty(Foo, 'num', 0);
return Foo;
}();
expect(Foo.num).toBe(0);
expect(Foo.num = 1).toBe(1);
expect(Foo.name).toBe('Foo');
"#
);

View File

@ -2,8 +2,9 @@ pub use self::{
arrow::arrow, block_scoped_fn::BlockScopedFns, block_scoping::block_scoping, classes::Classes,
computed_props::computed_properties, destructuring::destructuring,
duplicate_keys::duplicate_keys, for_of::for_of, function_name::function_name,
instanceof::InstanceOf, parameters::parameters, shorthand_property::Shorthand, spread::Spread,
sticky_regex::StickyRegex, template_literal::TemplateLiteral, typeof_symbol::TypeOfSymbol,
instanceof::InstanceOf, parameters::parameters, resolver::resolver,
shorthand_property::Shorthand, spread::Spread, sticky_regex::StickyRegex,
template_literal::TemplateLiteral, typeof_symbol::TypeOfSymbol,
};
use crate::{helpers::Helpers, pass::Pass};
use ast::{Expr, Module, Stmt};
@ -20,6 +21,7 @@ mod for_of;
mod function_name;
mod instanceof;
mod parameters;
mod resolver;
mod shorthand_property;
mod spread;
mod sticky_regex;
@ -53,18 +55,19 @@ pub fn es2015(helpers: &Arc<Helpers>) -> impl Pass + Clone {
fn stmts(helpers: &Arc<Helpers>) -> impl Pass + Clone {
chain_at!(
Stmt,
function_name(),
exprs(helpers),
Classes {
helpers: helpers.clone(),
},
BlockScopedFns,
function_name(),
parameters(),
)
}
chain_at!(
Module,
resolver(),
stmts(helpers),
for_of(),
computed_properties(helpers.clone()),

View File

@ -26,8 +26,7 @@ impl Params {
match param {
Pat::Ident(..) => params.push(param),
Pat::Array(..) | Pat::Object(..) => {
let mark = Mark::fresh(Mark::root());
let binding = quote_ident!(span.apply_mark(mark), "param");
let binding = private_ident!(span, "param");
params.push(Pat::Ident(binding.clone()));
decls.push(VarDeclarator {
@ -38,8 +37,7 @@ impl Params {
})
}
Pat::Assign(..) => {
let mark = Mark::fresh(Mark::root());
let binding = quote_ident!(span.apply_mark(mark), "param");
let binding = private_ident!(span, "param");
params.push(Pat::Ident(binding.clone()));
// This expands to invalid code, but is fixed by destructing pass

View File

@ -4,9 +4,10 @@ use std::sync::Arc;
fn tr(helpers: Arc<Helpers>) -> impl Fold<Module> {
chain!(
crate::compat::es2015::resolver(),
Params,
crate::compat::es2015::destructuring(helpers.clone()),
crate::compat::es2015::block_scoping()
crate::compat::es2015::block_scoping(),
)
}

View File

@ -0,0 +1,336 @@
use crate::scope::ScopeKind;
use ast::*;
use fnv::FnvHashSet;
use swc_atoms::JsWord;
use swc_common::{Fold, FoldWith, Mark, SyntaxContext};
#[cfg(test)]
mod tests;
const LOG: bool = true;
pub fn resolver() -> Resolver<'static> {
Resolver::new(
Mark::fresh(Mark::root()),
Scope::new(ScopeKind::Fn, None),
None,
)
}
#[derive(Debug, Clone)]
struct Scope<'a> {
/// Parent scope of this scope
parent: Option<&'a Scope<'a>>,
/// Kind of the scope.
kind: ScopeKind,
/// All references declared in this scope
declared_symbols: FnvHashSet<JsWord>,
}
impl<'a> Scope<'a> {
pub fn new(kind: ScopeKind, parent: Option<&'a Scope<'a>>) -> Self {
Scope {
parent,
kind,
declared_symbols: Default::default(),
}
}
}
#[derive(Clone)]
pub struct Resolver<'a> {
mark: Mark,
current: Scope<'a>,
cur_defining: Option<(JsWord, Mark)>,
in_var_decl: bool,
}
impl<'a> Resolver<'a> {
fn new(mark: Mark, current: Scope<'a>, cur_defining: Option<(JsWord, Mark)>) -> Self {
Resolver {
mark,
current,
cur_defining,
in_var_decl: false,
}
}
fn mark_for(&self, sym: &JsWord) -> Option<Mark> {
let mut mark = self.mark;
let mut scope = Some(&self.current);
while let Some(cur) = scope {
if cur.declared_symbols.contains(sym) {
if mark == Mark::root() {
return None;
}
return Some(mark);
}
mark = mark.parent();
scope = cur.parent;
}
None
}
fn fold_binding_ident(&mut self, ident: Ident) -> Ident {
if cfg!(debug_assertions) && LOG {
eprintln!("resolver: Binding {}{:?}", ident.sym, ident.span.ctxt());
}
if ident.span.ctxt() != SyntaxContext::empty() {
return ident;
}
let (should_insert, mark) = if let Some((ref cur, override_mark)) = self.cur_defining {
if *cur != ident.sym {
(true, self.mark)
} else {
(false, override_mark)
}
} else {
(true, self.mark)
};
if should_insert {
self.current.declared_symbols.insert(ident.sym.clone());
}
Ident {
span: if mark == Mark::root() {
ident.span
} else {
eprintln!("\t-> {:?}", mark);
ident.span.apply_mark(mark)
},
sym: ident.sym,
..ident
}
}
}
impl<'a> Fold<Function> for Resolver<'a> {
fn fold(&mut self, mut f: Function) -> Function {
let child_mark = Mark::fresh(self.mark);
// Child folder
let mut folder = Resolver::new(
child_mark,
Scope::new(ScopeKind::Fn, Some(&self.current)),
self.cur_defining.take(),
);
folder.in_var_decl = true;
f.params = f.params.fold_with(&mut folder);
folder.in_var_decl = false;
f.body = f.body.map(|stmt| stmt.fold_children(&mut folder));
self.cur_defining = folder.cur_defining;
f
}
}
impl<'a> Fold<BlockStmt> for Resolver<'a> {
fn fold(&mut self, block: BlockStmt) -> BlockStmt {
let child_mark = Mark::fresh(self.mark);
let mut child_folder = Resolver::new(
child_mark,
Scope::new(ScopeKind::Block, Some(&self.current)),
self.cur_defining.take(),
);
let block = block.fold_children(&mut child_folder);
self.cur_defining = child_folder.cur_defining;
block
}
}
impl<'a> Fold<FnExpr> for Resolver<'a> {
fn fold(&mut self, e: FnExpr) -> FnExpr {
let ident = if let Some(ident) = e.ident {
Some(self.fold_binding_ident(ident))
} else {
None
};
let function = e.function.fold_with(self);
FnExpr { ident, function }
}
}
impl<'a> Fold<FnDecl> for Resolver<'a> {
fn fold(&mut self, node: FnDecl) -> FnDecl {
let ident = self.fold_binding_ident(node.ident);
let function = node.function.fold_with(self);
FnDecl {
ident,
function,
..node
}
}
}
impl<'a> Fold<Expr> for Resolver<'a> {
fn fold(&mut self, expr: Expr) -> Expr {
let old_in_var_decl = self.in_var_decl;
self.in_var_decl = false;
let expr = match expr {
// Leftmost one of a member expression shoukld be resolved.
Expr::Member(me) => {
if me.computed {
Expr::Member(MemberExpr {
obj: me.obj.fold_with(self),
prop: me.prop.fold_with(self),
..me
})
} else {
Expr::Member(MemberExpr {
obj: me.obj.fold_with(self),
..me
})
}
}
_ => expr.fold_children(self),
};
self.in_var_decl = old_in_var_decl;
expr
}
}
impl<'a> Fold<VarDeclarator> for Resolver<'a> {
fn fold(&mut self, decl: VarDeclarator) -> VarDeclarator {
// order is important
let old_in_var_decl = self.in_var_decl;
self.in_var_decl = true;
let name = decl.name.fold_with(self);
self.in_var_decl = old_in_var_decl;
let cur_name = match name {
Pat::Ident(Ident { ref sym, .. }) => Some((sym.clone(), self.mark)),
_ => None,
};
let is_class_like = match decl.init {
Some(box Expr::Fn(FnExpr { ref ident, .. }))
if cur_name.is_some()
&& ident.as_ref().map(|v| &v.sym) == cur_name.as_ref().map(|v| &v.0) =>
{
true
}
Some(box Expr::Call(CallExpr {
callee: ExprOrSuper::Expr(box Expr::Fn(FnExpr { ident: None, .. })),
..
}))
| Some(box Expr::Call(CallExpr {
callee:
ExprOrSuper::Expr(box Expr::Paren(ParenExpr {
expr: box Expr::Fn(FnExpr { ident: None, .. }),
..
})),
..
})) => true,
_ => false,
};
if !is_class_like {
dbg!(&decl.init);
}
let old_def = self.cur_defining.take();
self.cur_defining = if is_class_like { cur_name } else { None };
let init = decl.init.fold_children(self);
self.cur_defining = old_def;
VarDeclarator { name, init, ..decl }
}
}
impl<'a> Fold<Ident> for Resolver<'a> {
fn fold(&mut self, i: Ident) -> Ident {
if self.in_var_decl {
self.fold_binding_ident(i)
} else {
let Ident { span, sym, .. } = i;
if cfg!(debug_assertions) && LOG {
eprintln!("resolver: IdentRef {}{:?}", sym, i.span.ctxt());
}
if span.ctxt() != SyntaxContext::empty() {
return Ident { sym, ..i };
}
if let Some(mark) = self.mark_for(&sym) {
if cfg!(debug_assertions) && LOG {
eprintln!("\t -> {:?}", mark);
}
Ident {
sym,
span: span.apply_mark(mark),
..i
}
} else {
// Cannot resolve reference. (TODO: Report error)
Ident { sym, span, ..i }
}
}
}
}
impl<'a> Fold<ArrowExpr> for Resolver<'a> {
fn fold(&mut self, e: ArrowExpr) -> ArrowExpr {
let old_in_var_decl = self.in_var_decl;
self.in_var_decl = true;
let params = e.params.fold_with(self);
self.in_var_decl = old_in_var_decl;
let body = e.body.fold_with(self);
ArrowExpr { params, body, ..e }
}
}
impl<'a> Fold<Constructor> for Resolver<'a> {
fn fold(&mut self, c: Constructor) -> Constructor {
let old_in_var_decl = self.in_var_decl;
self.in_var_decl = true;
let params = c.params.fold_with(self);
self.in_var_decl = old_in_var_decl;
let body = c.body.fold_with(self);
let key = c.key.fold_with(self);
Constructor {
params,
body,
key,
..c
}
}
}
impl<'a> Fold<CatchClause> for Resolver<'a> {
fn fold(&mut self, c: CatchClause) -> CatchClause {
let old_in_var_decl = self.in_var_decl;
self.in_var_decl = true;
let param = c.param.fold_with(self);
self.in_var_decl = old_in_var_decl;
let body = c.body.fold_with(self);
CatchClause { param, body, ..c }
}
}

View File

@ -0,0 +1,602 @@
use super::*;
use crate::compat::es2015::block_scoping;
fn tr() -> impl Fold<Module> {
chain!(resolver(), block_scoping())
}
macro_rules! identical {
($name:ident, $src:literal) => {
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
$name,
$src,
$src
);
};
}
#[test]
fn test_mark_for() {
::testing::run_test(false, |_, _| {
let mark1 = Mark::fresh(Mark::root());
let mark2 = Mark::fresh(mark1);
let mark3 = Mark::fresh(mark2);
let mark4 = Mark::fresh(mark3);
let folder1 = Resolver::new(mark1, Scope::new(ScopeKind::Block, None), None);
let mut folder2 = Resolver::new(
mark2,
Scope::new(ScopeKind::Block, Some(&folder1.current)),
None,
);
folder2.current.declared_symbols.insert("foo".into());
let mut folder3 = Resolver::new(
mark3,
Scope::new(ScopeKind::Block, Some(&folder2.current)),
None,
);
folder3.current.declared_symbols.insert("bar".into());
assert_eq!(folder3.mark_for(&"bar".into()), Some(mark3));
let mut folder4 = Resolver::new(
mark4,
Scope::new(ScopeKind::Block, Some(&folder3.current)),
None,
);
folder4.current.declared_symbols.insert("foo".into());
assert_eq!(folder4.mark_for(&"foo".into()), Some(mark4));
assert_eq!(folder4.mark_for(&"bar".into()), Some(mark3));
Ok(())
})
.unwrap();
}
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
basic_no_usage,
"
let foo;
{
let foo;
}
",
"
var foo;
{
var foo1;
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
class_nested_var,
"
var ConstructorScoping = function ConstructorScoping() {
_classCallCheck(this, ConstructorScoping);
var bar;
{
var bar;
}
}
",
"
var ConstructorScoping = function ConstructorScoping() {
_classCallCheck(this, ConstructorScoping);
var bar;
{
var bar1;
}
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
basic,
r#"
{
var foo = 1;
{
let foo = 2;
use(foo);
}
use(foo)
}
"#,
r#"
{
var foo = 1;
{
var foo1 = 2;
use(foo1);
}
use(foo);
}
"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
general_assignment_patterns,
r#"const foo = "foo";
function foobar() {
for (let item of [1, 2, 3]) {
let foo = "bar";
[bar, foo] = [1, 2];
}
}"#,
r#"var foo = "foo";
function foobar() {
for (var item of [1, 2, 3]) {
var foo1 = "bar";
[bar, foo1] = [1, 2];
}
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
general_function,
r#"function test() {
let foo = "bar";
}"#,
r#"function test() {
var foo = "bar";
}"#
);
test!(
ignore,
::swc_ecma_parser::Syntax::default(),
tr(),
babel_issue_1051,
r#"foo.func1 = function() {
if (cond1) {
for (;;) {
if (cond2) {
function func2() {}
function func3() {}
func4(function() {
func2();
});
break;
}
}
}
};"#,
r#"foo.func1 = function () {
if (cond1) {
for (;;) {
if (cond2) {
var _ret = function () {
function func2() {}
function func3() {}
func4(function () {
func2();
});
return "break";
}();
if (_ret === "break") break;
}
}
}
};"#
);
test!(
ignore,
::swc_ecma_parser::Syntax::default(),
// TODO(kdy1): WTF is this (again)?
tr(),
babel_issue_2174,
r#"if (true) {
function foo() {}
function bar() {
return foo;
}
for (var x in {}) {}
}"#,
r#"
if (true) {
var foo = function () {};
var bar = function () {
return foo;
};
for (var x in {}) {}
}"#
);
test!(
ignore,
::swc_ecma_parser::Syntax::default(),
tr(),
babel_issue_4363,
r#"function WithoutCurlyBraces() {
if (true)
for (let k in kv) {
function foo() { return this }
function bar() { return foo.call(this) }
console.log(this, k) // => undefined
}
}
function WithCurlyBraces() {
if (true) {
for (let k in kv) {
function foo() { return this }
function bar() { return foo.call(this) }
console.log(this, k) // => 777
}
}
}"#,
r#"function WithoutCurlyBraces() {
var _this = this;
if (true) {
var _loop = function (k) {
function foo() {
return this;
}
function bar() {
return foo.call(this);
}
console.log(_this, k); // => undefined
};
for (var k in kv) {
_loop(k);
}
}
}
function WithCurlyBraces() {
var _this2 = this;
if (true) {
var _loop2 = function (k) {
function foo() {
return this;
}
function bar() {
return foo.call(this);
}
console.log(_this2, k); // => 777
};
for (var k in kv) {
_loop2(k);
}
}
}"#
);
test!(
// Cannot represent function expression without parens (in result code)
ignore,
::swc_ecma_parser::Syntax::default(),
tr(),
babel_issue_4946,
r#"(function foo() {
let foo = true;
});"#,
r#"(function foo() {
var foo = true;
});"#
);
// TODO: try {} catch (a) { let a } should report error
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
babel_issue_973,
r#"let arr = [];
for(let i = 0; i < 10; i++) {
for (let i = 0; i < 10; i++) {
arr.push(() => i);
}
}
"#,
r#"var arr = [];
for(var i = 0; i < 10; i++){
for(var i1 = 0; i1 < 10; i1++){
arr.push(()=>i1);
}
}"#
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| tr(),
pass_assignment,
r#"let a = 1;
a = 2;
expect(a).toBe(2);"#
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| tr(),
pass_call,
r#"let a = 1;
function b() {
return a + 1;
}
expect(b()).toBe(2);"#
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| tr(),
pass_update,
r#"let a = 1;
a++;
expect(a).toBe(2);"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
fn_param,
r#"let a = 'foo';
function foo(a) {
use(a);
}"#,
r#"var a = 'foo';
function foo(a1) {
use(a1);
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
fn_body,
r#"let a = 'foo';
function foo() {
let a = 'bar';
use(a);
}"#,
r#"var a = 'foo';
function foo() {
var a1 = 'bar';
use(a1);
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
shorthand,
r#"let a = 'foo';
function foo() {
let a = 'bar';
use({a});
}"#,
r#"var a = 'foo';
function foo() {
var a1 = 'bar';
use({a: a1});
}"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
same_level,
r#"
var a = 'foo';
var a = 'bar';
"#,
r#"
var a = 'foo';
var a = 'bar';
"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
class_block,
r#"
var Foo = function(_Bar) {
_inherits(Foo, _Bar);
function Foo() {
}
return Foo;
}(Bar);
"#,
r#"
var Foo = function(_Bar) {
_inherits(Foo, _Bar);
function Foo() {
}
return Foo;
}(Bar);
"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
class_block_2,
r#"
var Foo = (function(_Bar) {
_inherits(Foo, _Bar);
function Foo() {
}
return Foo;
})(Bar);
"#,
r#"
var Foo = function(_Bar) {
_inherits(Foo, _Bar);
function Foo() {
}
return Foo;
}(Bar);
"#
);
test!(
::swc_ecma_parser::Syntax::default(),
tr(),
class_nested,
r#"
var Outer = function(_Hello) {
_inherits(Outer, _Hello);
function Outer() {
_classCallCheck(this, Outer);
var _this = _possibleConstructorReturn(this, _getPrototypeOf(Outer).call(this));
var Inner = function() {
function Inner() {
_classCallCheck(this, Inner);
}
_createClass(Inner, [{
key: _get(_getPrototypeOf(Outer.prototype), 'toString', _assertThisInitialized(_this)).call(_this), value: function() {
return 'hello';
}
}]);
return Inner;
}();
return _possibleConstructorReturn(_this, new Inner());
}
return Outer;
}(Hello);
"#,
r#"
var Outer = function(_Hello) {
_inherits(Outer, _Hello);
function Outer() {
_classCallCheck(this, Outer);
var _this = _possibleConstructorReturn(this, _getPrototypeOf(Outer).call(this));
var Inner = function() {
function Inner() {
_classCallCheck(this, Inner);
}
_createClass(Inner, [{
key: _get(_getPrototypeOf(Outer.prototype), 'toString', _assertThisInitialized(_this)).call(_this), value: function() {
return 'hello';
}
}]);
return Inner;
}();
return _possibleConstructorReturn(_this, new Inner());
}
return Outer;
}(Hello);
"#
);
identical!(class_var_constructor_only, r#"var Foo = function Foo(){}"#);
identical!(
class_var,
r#"
var Foo = function(_Bar) {
_inherits(Foo, _Bar);
function Foo() {
var _this;
_classCallCheck(this, Foo);
Foo[_assertThisInitialized(_this)];
return _possibleConstructorReturn(_this);
}
return Foo;
}(Bar);
"#
);
identical!(
class_singleton,
r#"
var singleton;
var Sub = function(_Foo) {
_inherits(Sub, _Foo);
function Sub() {
var _this;
_classCallCheck(this, Sub);
if (singleton) {
return _possibleConstructorReturn(_this, singleton);
}
singleton = _this = _possibleConstructorReturn(this, _getPrototypeOf(Sub).call(this));
return _possibleConstructorReturn(_this);
}
return Sub;
}(Foo);
"#
);
identical!(
regression_001,
"var sym = Symbol();
class Foo {
[sym] () {
return 1;
}
}
class Bar extends Foo {
[sym] () {
return super[sym]() + 2;
}
}
var i = new Bar();
expect(i[sym]()).toBe(3);"
);
identical!(
regression_002,
"var sym = Symbol();
var Foo = function() {
function Foo() {
_classCallCheck(this, Foo);
}
_createClass(Foo, [{
key: sym, value: function() {
return 1;
}
}]);
return Foo;
}();
var Bar = function(_Foo) {
_inherits(Bar, _Foo);
function Bar() {
_classCallCheck(this, Bar);
return _possibleConstructorReturn(this, _getPrototypeOf(Bar).apply(this, arguments));
}
_createClass(Bar, [{
key: sym, value: function() {
return _get(_getPrototypeOf(Bar.prototype), sym, this)() + 2;
}
}]);
return Bar;
}(Foo);
var i = new Bar();
expect(i[sym]()).toBe(3);"
);

View File

@ -87,9 +87,11 @@ impl Fold<Expr> for Spread {
Expr::New(NewExpr {
span,
callee: box member_expr!(span, Function.prototype.bind)
.apply(span, callee, vec![args.as_arg()])
.wrap_with_paren(),
callee: box member_expr!(span, Function.prototype.bind).apply(
span,
callee,
vec![args.as_arg()],
),
args: Some(vec![]),
type_args,
})
@ -234,8 +236,9 @@ mod tests {
Spread::default(),
new,
"new C(a, b, c, ...d, e)",
"new (Function.prototype.bind.apply(C, [null, a, b, c].concat(_toConsumableArray(d), \
[e])))();"
"new Function.prototype.bind.apply(C, [null, a, b, c].concat(_toConsumableArray(d), \
[e]))();",
ok_if_code_eq
);
test!(

View File

@ -1,7 +1,7 @@
use crate::{helpers::Helpers, util::ExprFactory};
use ast::*;
use std::{iter, sync::Arc};
use swc_common::{Fold, FoldWith, Mark, Spanned, DUMMY_SP};
use swc_common::{Fold, FoldWith, Spanned, DUMMY_SP};
#[cfg(test)]
mod tests;
@ -70,8 +70,7 @@ impl Fold<Expr> for TemplateLiteral {
assert!(quasis.len() == exprs.len() + 1);
self.helpers.tagged_template_literal();
let mark = Mark::fresh(Mark::root());
let fn_ident = quote_ident!(DUMMY_SP.apply_mark(mark), "_templateObject");
let fn_ident = private_ident!("_templateObject");
let tpl_obj_fn = {
Expr::Fn(FnExpr {

View File

@ -3,7 +3,7 @@ use crate::{
util::{ExprFactory, StmtLike},
};
use ast::*;
use swc_common::{Fold, FoldWith, Mark, Span, Spanned, Visit, VisitWith, DUMMY_SP};
use swc_common::{Fold, FoldWith, Span, Spanned, Visit, VisitWith, DUMMY_SP};
/// `@babel/plugin-transform-exponentiation-operator`
///
@ -52,15 +52,15 @@ impl Fold<Expr> for AssignFolder {
// unimplemented
PatOrExpr::Expr(ref e) => {
let mark = Mark::fresh(Mark::root());
let span = e.span().apply_mark(mark);
let ref_ident = private_ident!(e.span(), "ref");
self.vars.push(VarDeclarator {
span: DUMMY_SP,
name: quote_ident!(span, "ref").into(),
name: ref_ident.clone().into(),
init: Some(e.clone()),
definite: false,
});
quote_ident!(span, "ref")
ref_ident
}
left => {

View File

@ -487,8 +487,7 @@ impl Actual {
let params = f.params.clone();
let ident = raw_ident.clone().unwrap_or_else(|| quote_ident!("ref"));
let mark = Mark::fresh(Mark::root());
let real_fn_ident = quote_ident!(ident.span.apply_mark(mark), format!("_{}", ident.sym));
let real_fn_ident = private_ident!(ident.span, format!("_{}", ident.sym));
let right = make_fn_ref(
&self.helpers,
FnExpr {

View File

@ -49,7 +49,7 @@ let TestClass = {
let TestClass = {
name: 'John Doe',
testMethodFailure () {
return new Promise((function(resolve) {
return new Promise(function(resolve) {
var _ref = _asyncToGenerator((function*(resolve) {
console.log(this);
setTimeout(resolve, 1000);
@ -57,7 +57,7 @@ let TestClass = {
return function() {
return _ref.apply(this, arguments);
};
})().bind(this));
}().bind(this));
}
};
"#
@ -181,29 +181,29 @@ function _s() {
for(let _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++){
args[_key - 1] = arguments[_key];
}
let t = (function(y, a) {
var _t = _asyncToGenerator((function*(y, a) {
let r = (function(z, b) {
var _ref = _asyncToGenerator((function*(z, b) {
for(let _len = arguments.length, innerArgs = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++){
innerArgs[_key - 2] = arguments[_key];
let t = function(y, a) {
var _ref = _asyncToGenerator((function*(y, a) {
let r = function(z, b) {
var _ref1 = _asyncToGenerator((function*(z, b) {
for(let _len1 = arguments.length, innerArgs = new Array(_len1 > 2 ? _len1 - 2 : 0), _key1 = 2; _key1 < _len1; _key1++){
innerArgs[_key1 - 2] = arguments[_key1];
}
yield z;
console.log(this, innerArgs, arguments);
return this.x;
}).bind(this));
return function() {
return _ref.apply(this, arguments);
return _ref1.apply(this, arguments);
};
})().bind(this);
}().bind(this);
yield r();
console.log(this, args, arguments);
return this.g(r);
}).bind(this));
return function t() {
return _t.apply(this, arguments);
return function () {
return _ref.apply(this, arguments);
};
})().bind(this);
}().bind(this);
yield t();
return this.h(t);
}).bind(this));
@ -296,7 +296,7 @@ function two(a, b) {
}
function _three() {
_three = _asyncToGenerator(function*(a, param, c, param1) {
let tmp = param, b = tmp === void 0 ? 1 : tmp, tmp = param1, d = tmp === void 0 ? 3 : tmp;
let tmp = param, b = tmp === void 0 ? 1 : tmp, tmp1 = param1, d = tmp1 === void 0 ? 3 : tmp1;
});
return _three.apply(this, arguments);
}
@ -327,7 +327,7 @@ function five(a, param) {
function _six() {
_six = _asyncToGenerator(function*(a, param) {
let tmp = param, ref = tmp === void 0 ? {
} : tmp, ref = ref ? ref : _throw(new TypeError("Cannot destructure 'undefined' or 'null'")), b = ref.b;
} : tmp, ref1 = ref ? ref : _throw(new TypeError("Cannot destructure 'undefined' or 'null'")), b = ref1.b;
});
return _six.apply(this, arguments);
}
@ -347,14 +347,14 @@ var foo = async function bar() {
};
"#,
r#"
var foo = (function() {
var foo = function() {
var _bar = _asyncToGenerator(function*() {
console.log(bar);
});
return function bar() {
return _bar.apply(this, arguments);
};
})();
}();
"#
);
@ -366,13 +366,13 @@ test!(
foo(async function () {
});"#,
r#"
foo((function() {
foo(function() {
var _ref = _asyncToGenerator(function*() {
});
return function() {
return _ref.apply(this, arguments);
};
})());
}());
"#
);

Some files were not shown because too many files have changed in this diff Show More