parcel icon indicating copy to clipboard operation
parcel copied to clipboard

"@parcel/transformer-js: Expected ';', '}' or <eof>" on code that compiles well in another project

Open dariocravero opened this issue 2 years ago • 1 comments

🐛 bug report

Trying to add parcel v2 to a somewhat large codebase. The repo is a yarn monorepo and the relevant part to parcel are two folders:

- apps/admin
- design-system

apps/admin is the root of one of the apps and it uses design-system as package.

Parcel fails to run/build the code referencing a syntax error but the code is fine and compiles when processed by parcel on a smaller project.

🎛 Configuration (.babelrc, package.json, cli command)

None

🤔 Expected Behavior

It should parse files in design-system since the file compiles in a regular project.

😯 Current Behavior

It fails with this error:

🚨 Build failed.

@parcel/transformer-js: Expected ';', '}' or <eof>

  /Users/dario/greyfinch/greyfinch/design-system/LoadingBar/view.js:31:14
    30 | <Timeout
  > 31 |   data-testid="LoadingBar.Timeout"
  >    |              ^
    32 |   data-view-path="/DesignSystem/LoadingBar"
    33 |   viewPath={`${viewPath}/Timeout`}

💁 Possible Solution

More than a possible solution this is a gut feeling I'm getting here. I think the problem could be related to the amount of files. Within the two folders there are about 1k JS files, I don't think it's necessarily that much but it could be? Particularly taking into account that a similar setup at a smaller scale (about 10 files) worked out alright. Deleting .parcel-cache doesn't have any effect on it. I'm also aware of the issue with symlink in #4332 but I don't think this is the problem here, because even if I move the symlinked design-system folder into I still get the same error.

🔦 Context

Just trying to test parcel on the project.

💻 Code Sample

I tried making a code sample but can't reproduce it and unfortunately I can't share this codebase since it's private. If you have any suggestions by which I could share it, happy to do so!

🌍 Your Environment

Software Version(s)
Parcel 2.2.1
Node 14.18.1
Yarn 1.22.4
Operating System macOS Big sur 11.5.2

Thanks!

dariocravero avatar Jan 31 '22 11:01 dariocravero

I would say this is because Parcel doesn't think that design-system/LoadingBar/view.js contains JSX. Usually that gets enabled when react/preact/... is detected in package.json

I tried making a code sample but can't reproduce it and unfortunately I can't share this codebase since it's private. If you have any suggestions by which I could share it, happy to do so!

I'd try keeping the folder structure (including package.json) as is and removing unrelated source files.

mischnic avatar Jul 21 '22 12:07 mischnic

same here when using "recharts": "^2.2.0"! Marked is the {

@parcel/transformer-js: Expected '>', got '{'

rectangle = <Rectangle {...props} />;

Lueton avatar Dec 17 '22 16:12 Lueton

@Lueton Please share the whole file that fails to parse for you.

mischnic avatar Dec 17 '22 16:12 mischnic

@Lueton Please share the whole file that fails to parse for you.

Below is the content of the file. As short explanation im using recharts in a project and as soon as i use some of the recharts packages (in this case BarChart) im getting this error (line 290).

node_modules\recharts\src\cartesian\Bar.tsx:290:30

/**
 * @fileOverview Render a group of bar
 */
import React, { PureComponent, ReactElement } from 'react';
import classNames from 'classnames';
import Animate from 'react-smooth';
import _ from 'lodash';
import { Rectangle, Props as RectangleProps } from '../shape/Rectangle';
import { Layer } from '../container/Layer';
import { ErrorBar, Props as ErrorBarProps } from './ErrorBar';
import { Cell } from '../component/Cell';
import { LabelList } from '../component/LabelList';
import { uniqueId, mathSign, interpolateNumber } from '../util/DataUtils';
import { findAllByType } from '../util/ReactUtils';
import { Global } from '../util/Global';
import {
  getCateCoordinateOfBar,
  getValueByDataKey,
  truncateByDomain,
  getBaseValueOfBar,
  findPositionOfBar,
  getTooltipItem,
} from '../util/ChartUtils';
import { Props as XAxisProps } from './XAxis';
import { Props as YAxisProps } from './YAxis';
import {
  D3Scale,
  TooltipType,
  LegendType,
  AnimationTiming,
  filterProps,
  ChartOffset,
  DataKey,
  TickItem,
  adaptEventsOfChild,
  PresentationAttributesAdaptChildEvent,
} from '../util/types';
import { ImplicitLabelType } from '../component/Label';

interface BarRectangleItem extends RectangleProps {
  value?: number;
  /** the coordinate of background rectangle */
  background?: {
    x?: number;
    y?: number;
    width?: number;
    height?: number;
  };
}

interface InternalBarProps {
  xAxis?: Omit<XAxisProps, 'scale'> & { scale: D3Scale<string | number>; x?: number; width?: number };
  yAxis?: Omit<YAxisProps, 'scale'> & { scale: D3Scale<string | number>; y?: number; height?: number };
  data?: BarRectangleItem[];
  top?: number;
  left?: number;
}

type RectangleShapeType =
  | ReactElement<SVGElement>
  | ((props: any) => ReactElement<SVGElement>)
  | RectangleProps
  | boolean;

interface BarProps extends InternalBarProps {
  className?: string;
  layout?: 'horizontal' | 'vertical';
  xAxisId?: string | number;
  yAxisId?: string | number;
  stackId?: string | number;
  barSize?: number;
  unit?: string | number;
  name?: string | number;
  dataKey: DataKey<any>;
  tooltipType?: TooltipType;
  legendType?: LegendType;
  minPointSize?: number;
  maxBarSize?: number;
  hide?: boolean;
  shape?: ReactElement<SVGElement> | ((props: any) => ReactElement<SVGElement>);
  background?: RectangleShapeType;
  radius?: number | [number, number, number, number];

  onAnimationStart?: () => void;
  onAnimationEnd?: () => void;

  isAnimationActive?: boolean;
  animationBegin?: number;
  animationDuration?: number;
  animationEasing?: AnimationTiming;
  animationId?: number;
  id?: string;
  label?: ImplicitLabelType;
}

export type Props = Omit<PresentationAttributesAdaptChildEvent<any, SVGPathElement>, 'radius'> & BarProps;

interface State {
  readonly isAnimationFinished?: boolean;
  readonly prevData?: BarRectangleItem[];
  readonly curData?: BarRectangleItem[];
  readonly prevAnimationId?: number;
}

export class Bar extends PureComponent<Props, State> {
  static displayName = 'Bar';

  static defaultProps = {
    xAxisId: 0,
    yAxisId: 0,
    legendType: 'rect',
    minPointSize: 0,
    hide: false,
    // data of bar
    data: [] as BarRectangleItem[],
    layout: 'vertical',
    isAnimationActive: !Global.isSsr,
    animationBegin: 0,
    animationDuration: 400,
    animationEasing: 'ease',
  };

  /**
   * Compose the data of each group
   * @param {Object} props Props for the component
   * @param {Object} item        An instance of Bar
   * @param {Array} barPosition  The offset and size of each bar
   * @param {Object} xAxis       The configuration of x-axis
   * @param {Object} yAxis       The configuration of y-axis
   * @param {Array} stackedData  The stacked data of a bar item
   * @return{Array} Composed data
   */
  static getComposedData = ({
    props,
    item,
    barPosition,
    bandSize,
    xAxis,
    yAxis,
    xAxisTicks,
    yAxisTicks,
    stackedData,
    dataStartIndex,
    displayedData,
    offset,
  }: {
    props: Props;
    item: Bar;
    barPosition: any;
    bandSize: number;
    xAxis: InternalBarProps['xAxis'];
    yAxis: InternalBarProps['yAxis'];
    xAxisTicks: TickItem[];
    yAxisTicks: TickItem[];
    stackedData: number[][];
    dataStartIndex: number;
    offset: ChartOffset;
    displayedData: any[];
  }) => {
    const pos = findPositionOfBar(barPosition, item);
    if (!pos) {
      return null;
    }

    const { layout } = props;
    const { dataKey, children, minPointSize } = item.props;
    const numericAxis = layout === 'horizontal' ? yAxis : xAxis;
    const stackedDomain = stackedData ? numericAxis.scale.domain() : null;
    const baseValue = getBaseValueOfBar({ numericAxis });
    const cells = findAllByType(children, Cell.displayName);

    const rects = displayedData.map((entry, index) => {
      let value, x, y, width, height, background;

      if (stackedData) {
        value = truncateByDomain(stackedData[dataStartIndex + index], stackedDomain);
      } else {
        value = getValueByDataKey(entry, dataKey);

        if (!_.isArray(value)) {
          value = [baseValue, value];
        }
      }

      if (layout === 'horizontal') {
        x = getCateCoordinateOfBar({
          axis: xAxis,
          ticks: xAxisTicks,
          bandSize,
          offset: pos.offset,
          entry,
          index,
        });
        y = yAxis.scale(value[1]);
        width = pos.size;
        height = yAxis.scale(value[0]) - yAxis.scale(value[1]);
        background = { x, y: yAxis.y, width, height: yAxis.height };

        if (Math.abs(minPointSize) > 0 && Math.abs(height) < Math.abs(minPointSize)) {
          const delta = mathSign(height || minPointSize) * (Math.abs(minPointSize) - Math.abs(height));

          y -= delta;
          height += delta;
        }
      } else {
        x = xAxis.scale(value[0]);
        y = getCateCoordinateOfBar({
          axis: yAxis,
          ticks: yAxisTicks,
          bandSize,
          offset: pos.offset,
          entry,
          index,
        });
        width = xAxis.scale(value[1]) - xAxis.scale(value[0]);
        height = pos.size;
        background = { x: xAxis.x, y, width: xAxis.width, height };

        if (Math.abs(minPointSize) > 0 && Math.abs(width) < Math.abs(minPointSize)) {
          const delta = mathSign(width || minPointSize) * (Math.abs(minPointSize) - Math.abs(width));
          width += delta;
        }
      }

      return {
        ...entry,
        x,
        y,
        width,
        height,
        value: stackedData ? value : value[1],
        payload: entry,
        background,
        ...(cells && cells[index] && cells[index].props),
        tooltipPayload: [getTooltipItem(item, entry)],
        tooltipPosition: { x: x + width / 2, y: y + height / 2 },
      };
    });

    return { data: rects, layout, ...offset };
  };

  state: State = { isAnimationFinished: false };

  static getDerivedStateFromProps(nextProps: Props, prevState: State): State {
    if (nextProps.animationId !== prevState.prevAnimationId) {
      return {
        prevAnimationId: nextProps.animationId,
        curData: nextProps.data,
        prevData: prevState.curData,
      };
    }
    if (nextProps.data !== prevState.curData) {
      return {
        curData: nextProps.data,
      };
    }

    return null;
  }

  id = uniqueId('recharts-bar-');

  handleAnimationEnd = () => {
    const { onAnimationEnd } = this.props;
    this.setState({ isAnimationFinished: true });

    if (onAnimationEnd) {
      onAnimationEnd();
    }
  };

  handleAnimationStart = () => {
    const { onAnimationStart } = this.props;
    this.setState({ isAnimationFinished: false });

    if (onAnimationStart) {
      onAnimationStart();
    }
  };

  static renderRectangle(option: RectangleShapeType, props: any) {
    let rectangle;

    if (React.isValidElement(option)) {
      rectangle = React.cloneElement(option, props);
    } else if (_.isFunction(option)) {
      rectangle = option(props);
    } else {
      rectangle = <Rectangle {...props} />;
    }

    return rectangle;
  }

  renderRectanglesStatically(data: BarRectangleItem[]) {
    const { shape } = this.props;
    const baseProps = filterProps(this.props);

    return (
      data &&
      data.map((entry, i) => {
        const props = { ...baseProps, ...entry, index: i };

        return (
          <Layer
            className="recharts-bar-rectangle"
            {...adaptEventsOfChild(this.props, entry, i)}
            key={`rectangle-${i}`} // eslint-disable-line react/no-array-index-key
            role="img"
          >
            {Bar.renderRectangle(shape, props)}
          </Layer>
        );
      })
    );
  }

  renderRectanglesWithAnimation() {
    const {
      data,
      layout,
      isAnimationActive,
      animationBegin,
      animationDuration,
      animationEasing,
      animationId,
    } = this.props;
    const { prevData } = this.state;

    return (
      <Animate
        begin={animationBegin}
        duration={animationDuration}
        isActive={isAnimationActive}
        easing={animationEasing}
        from={{ t: 0 }}
        to={{ t: 1 }}
        key={`bar-${animationId}`}
        onAnimationEnd={this.handleAnimationEnd}
        onAnimationStart={this.handleAnimationStart}
      >
        {({ t }: { t: number }) => {
          const stepData = data.map((entry, index) => {
            const prev = prevData && prevData[index];

            if (prev) {
              const interpolatorX = interpolateNumber(prev.x, entry.x);
              const interpolatorY = interpolateNumber(prev.y, entry.y);
              const interpolatorWidth = interpolateNumber(prev.width, entry.width);
              const interpolatorHeight = interpolateNumber(prev.height, entry.height);

              return {
                ...entry,
                x: interpolatorX(t),
                y: interpolatorY(t),
                width: interpolatorWidth(t),
                height: interpolatorHeight(t),
              };
            }

            if (layout === 'horizontal') {
              const interpolatorHeight = interpolateNumber(0, entry.height);
              const h = interpolatorHeight(t);

              return {
                ...entry,
                y: entry.y + entry.height - h,
                height: h,
              };
            }

            const interpolator = interpolateNumber(0, entry.width);
            const w = interpolator(t);

            return { ...entry, width: w };
          });

          return <Layer>{this.renderRectanglesStatically(stepData)}</Layer>;
        }}
      </Animate>
    );
  }

  renderRectangles() {
    const { data, isAnimationActive } = this.props;
    const { prevData } = this.state;

    if (isAnimationActive && data && data.length && (!prevData || !_.isEqual(prevData, data))) {
      return this.renderRectanglesWithAnimation();
    }

    return this.renderRectanglesStatically(data);
  }

  renderBackground() {
    const { data } = this.props;
    const backgroundProps = filterProps(this.props.background);

    return data.map((entry, i) => {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { value, background, ...rest } = entry;

      if (!background) {
        return null;
      }

      const props = {
        ...rest,
        fill: '#eee',
        ...background,
        ...backgroundProps,
        ...adaptEventsOfChild(this.props, entry, i),
        index: i,
        key: `background-bar-${i}`,
        className: 'recharts-bar-background-rectangle',
      };

      return Bar.renderRectangle(this.props.background, props);
    });
  }

  renderErrorBar() {
    if (this.props.isAnimationActive && !this.state.isAnimationFinished) {
      return null;
    }

    const { data, xAxis, yAxis, layout, children } = this.props;
    const errorBarItems = findAllByType(children, ErrorBar.displayName);

    if (!errorBarItems) {
      return null;
    }

    const offset = layout === 'vertical' ? data[0].height / 2 : data[0].width / 2;

    function dataPointFormatter(dataPoint: BarRectangleItem, dataKey: Props['dataKey']) {
      return {
        x: dataPoint.x,
        y: dataPoint.y,
        value: dataPoint.value,
        errorVal: getValueByDataKey(dataPoint, dataKey),
      };
    }

    return errorBarItems.map((item: ReactElement<ErrorBarProps>, i: number) =>
      React.cloneElement(item, {
        key: `error-bar-${i}`, // eslint-disable-line react/no-array-index-key
        data,
        xAxis,
        yAxis,
        layout,
        offset,
        dataPointFormatter,
      }),
    );
  }

  render() {
    const {
      hide,
      data,
      className,
      xAxis,
      yAxis,
      left,
      top,
      width,
      height,
      isAnimationActive,
      background,
      id,
    } = this.props;
    if (hide || !data || !data.length) {
      return null;
    }

    const { isAnimationFinished } = this.state;
    const layerClass = classNames('recharts-bar', className);
    const needClip = (xAxis && xAxis.allowDataOverflow) || (yAxis && yAxis.allowDataOverflow);
    const clipPathId = _.isNil(id) ? this.id : id;

    return (
      <Layer className={layerClass}>
        {needClip ? (
          <defs>
            <clipPath id={`clipPath-${clipPathId}`}>
              <rect x={left} y={top} width={width} height={height} />
            </clipPath>
          </defs>
        ) : null}
        <Layer className="recharts-bar-rectangles" clipPath={needClip ? `url(#clipPath-${clipPathId})` : null}>
          {background ? this.renderBackground() : null}
          {this.renderRectangles()}
        </Layer>
        {this.renderErrorBar()}
        {(!isAnimationActive || isAnimationFinished) && LabelList.renderCallByParent(this.props, data)}
      </Layer>
    );
  }
}

Lueton avatar Dec 17 '22 16:12 Lueton

How are you importing recharts? It should not be using recharts\src\* but the files in recharts\es6\*

mischnic avatar Dec 17 '22 16:12 mischnic

How are you importing recharts? It should not be using recharts\src\* but the files in recharts\es6\*

Wow, I am ashamed of myself. Seems like at the time of importing recharts some configs were wrong so it got imported with src path. You are completely right, thats the issue! Thank you!

Lueton avatar Dec 17 '22 16:12 Lueton