progfay/scrapbox-parser

View on GitHub
src/block/node/GoogleMapNode.ts

Summary

Maintainability
A
1 hr
Test Coverage
A
100%
import { createNodeParser } from "./creator";
import { createPlainNode } from "./PlainNode";

import type { GoogleMapNode, PlainNode } from "./type";
import type { NodeCreator } from "./creator";

const placeFirstGoogleMapRegExp =
  /\[([^\]]*[^\s])\s+([NS]\d+(?:\.\d+)?,[EW]\d+(?:\.\d+)?(?:,Z\d+)?)\]/;
const coordFirstGoogleMapRegExp =
  /\[([NS]\d+(?:\.\d+)?,[EW]\d+(?:\.\d+)?(?:,Z\d+)?)(?:\s+([^\]]*[^\s]))?\]/;

interface Coordinate {
  latitude: number;
  longitude: number;
  zoom: number;
}

const parseCoordinate: (format: string) => Coordinate = (format) => {
  const [lat = "", lng = "", z = ""] = format.split(",");
  const latitude = parseFloat(lat.replace(/^N/, "").replace(/^S/, "-"));
  const longitude = parseFloat(lng.replace(/^E/, "").replace(/^W/, "-"));
  const zoom = /^Z\d+$/.test(z) ? parseInt(z.replace(/^Z/, ""), 10) : 14;
  return { latitude, longitude, zoom };
};

const createGoogleMapNode: NodeCreator<GoogleMapNode | PlainNode> = (
  raw,
  opts
) => {
  if (opts.context === "table") {
    return createPlainNode(raw, opts);
  }

  const match =
    raw.match(placeFirstGoogleMapRegExp) ??
    raw.match(coordFirstGoogleMapRegExp);
  if (match === null) return [];

  const isCoordFirst = raw.startsWith("[N") || raw.startsWith("[S");
  const [, coord = "", place = ""] = isCoordFirst
    ? match
    : [match[0], match[2], match[1]];
  const { latitude, longitude, zoom } = parseCoordinate(coord);

  const url =
    place !== ""
      ? `https://www.google.com/maps/place/${encodeURIComponent(
          place
        )}/@${latitude},${longitude},${zoom}z`
      : `https://www.google.com/maps/@${latitude},${longitude},${zoom}z`;

  return [
    {
      type: "googleMap",
      raw,
      latitude,
      longitude,
      zoom,
      place,
      url,
    },
  ];
};

export const GoogleMapNodeParser = createNodeParser(createGoogleMapNode, {
  parseOnNested: false,
  parseOnQuoted: true,
  patterns: [placeFirstGoogleMapRegExp, coordFirstGoogleMapRegExp],
});