[
  {
    "path": ".gitignore",
    "content": "### https://raw.github.com/github/gitignore/9f8e411bba17223b5a7744ace8f41cede6601c59/Global/OSX.gitignore\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\r\r\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n\n### https://raw.github.com/github/gitignore/9f8e411bba17223b5a7744ace8f41cede6601c59/node.gitignore\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules\njspm_packages\n\n# Optional npm cache directory\n.npm\n\n# Optional REPL history\n.node_repl_history\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 trkbt10\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# Mikan.js - 機械学習を用いていない日本語改行問題へのソリューション\nmikan.jsは、正規表現を用いた簡易形態素解析による、単語の改行問題への解決策を提供します。\n[demo](https://trkbt10.github.io/mikan.js/)\n\n## インストール\n`npm install mikanjs`\n\n## 使い方\n\nnodeで用いる場合\n\n```javascript\nconst mikan = require('mikanjs');\nconsole.log(mikan('常に最新、最高のモバイル。Androidを開発した同じチームから。'));\n/*\n<span style=\"display:inline-block\" role=\"presentation\">常に</span>\n<span style=\"display:inline-block\" role=\"presentation\">最新、</span>\n<span style=\"display:inline-block\" role=\"presentation\">最高の</span>\n<span style=\"display:inline-block\" role=\"presentation\">モバイル。</span>\n<span style=\"display:inline-block\" role=\"presentation\">Androidを</span>\n<span style=\"display:inline-block\" role=\"presentation\">開発した</span>\n<span style=\"display:inline-block\" role=\"presentation\">同じ</span>\n<span style=\"display:inline-block\" role=\"presentation\">チームから。</span>\n*/\n\nconsole.log(mikan.split('常に最新、最高のモバイル。Androidを開発した同じチームから。'));\n// ['常に', '最新、', '最高の', 'モバイル。', 'Androidを', '開発した', '同じ', 'チームから。']\n```\n\nWebで用いる場合\n\n```html\n<div id=\"sample\"></div>\n<script src=\"mikan.js\"></script>\n<script>\n  var sampleElement = document.getElementById('sample');\n  sampleElement.innerHTML = Mikan('常に最新、最高のモバイル。Androidを開発した同じチームから。');\n</script>\n```\n\nReactで用いる場合\n```javascript\n<div dangerouslySetInnerHTML={{__html : Mikan('常に最新、最高のモバイル。Androidを開発した同じチームから。')}} />\n```\n\nもしくは\n```javascript\n{Mikan.split('常に最新、最高のモバイル。Androidを開発した同じチームから。').map((text) => <span>{text}</span>)}\n```\n"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Demo</title>\n  <link href=\"//fonts.googleapis.com/css?family=RobotoDraft:100,300,400,500,700\" rel=\n    \"stylesheet\">\n  <script src=\"./mikan.js\"></script>\n</head>\n<body>\n  <input type=\"text\" placeholder=\"ここに文章を入力\" id=\"input\"/>\n  <div id=\"sample\">\n\n  </div>\n  <script>\n    var sampleElement = document.getElementById('sample');\n    var input = document.getElementById('input');\n\n    sampleElement.appendChild(mikanHTML('やりたいことのそばにいる'));\n    input.addEventListener('change', function(e) {\n      var result = mikanHTML(e.target.value);\n      while (sampleElement.firstChild) {\n        sampleElement.removeChild(sampleElement.firstChild);\n      }\n      sampleElement.appendChild(result);\n    });\n\n    function mikanHTML(sentence) {\n      var tokens = Mikan.split(sentence);\n      var container = document.createElement('div');\n      tokens.forEach(function(token) {\n        var sp = document.createElement('span');\n        var textNode = document.createTextNode(token);\n        sp.style.display = 'inline-block'\n        sp.style.whiteSpace = 'nowrap'\n\n        sp.appendChild(textNode);\n        container.appendChild(sp);\n      })\n      return container;\n    }\n  </script>\n  <style>\n  body {\n    background: #fff;\n    color: #444;\n    font: 300 16px/1.6 \"RobotoDraft\",arial,sans-serif;\n    -webkit-font-smoothing: antialiased;\n    position: relative;\n  }\n  #sample {\n    font-family: 'RobotoDraft', arial, sans-serif;\n    color: #444;\n    font-size: 56px;\n    font-weight: 300;\n    line-height: 1.25;\n    margin: 20px auto;\n    max-width: 900px;\n    text-align: center;\n  }\n  </style>\n</body>\n</html>\n"
  },
  {
    "path": "docs/mikan.js",
    "content": "\"use strict\";\n(function(root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD\n    define([], factory);\n  } else if (typeof exports === 'object') {\n    // commonjs\n    module.exports = factory();\n  } else {\n    // Browser globals\n    root.Mikan = factory();\n  }\n})(this, function() {\n\n  var joshi = /(でなければ|について|かしら|くらい|けれど|なのか|ばかり|ながら|ことよ|こそ|こと|さえ|しか|した|たり|だけ|だに|だの|つつ|ても|てよ|でも|とも|から|など|なり|ので|のに|ほど|まで|もの|やら|より|って|で|と|な|に|ね|の|も|は|ば|へ|や|わ|を|か|が|さ|し|ぞ|て)/g;\n  var keywords = /(\\&nbsp;|[a-zA-Z0-9]+\\.[a-z]{2,}|[一-龠々〆ヵヶゝ]+|[ぁ-んゝ]+|[ァ-ヴー]+|[a-zA-Z0-9]+|[ａ-ｚＡ-Ｚ０-９]+)/g;\n  var periods = /([\\.\\,。、！\\!？\\?]+)$/g\n  var bracketsBegin = /([〈《「『｢（(\\[【〔〚〖〘❮❬❪❨(<{❲❰｛❴])/g\n  var bracketsEnd = /([〉》」』｣)）\\]】〕〗〙〛}>\\)❩❫❭❯❱❳❵｝])/g\n\n\n\n  function SimpleAnalyze(str) {\n    var words = str.split(keywords).reduce(function(prev, word) {\n      return [].concat(prev, word.split(joshi));\n    }).reduce(function(prev, word) {\n      return [].concat(prev, word.split(bracketsBegin));\n    }).reduce(function(prev, word) {\n      return [].concat(prev, word.split(bracketsEnd));\n    }).filter(function(word) {\n      return word;\n    });\n    var result = [];\n    var prevType = '';\n    var prevWord = '';\n    words.forEach(function(word) {\n      var token = word.match(periods) || word.match(joshi)\n\n      if (word.match(bracketsBegin)) {\n        prevType = 'bracketBegin';\n        prevWord = word;\n        return\n      }\n      if (word.match(bracketsEnd)) {\n        result[result.length - 1] += word;\n        prevType = 'bracketEnd';\n        prevWord = word;\n        return\n      }\n\n      if (prevType === 'bracketBegin') {\n        word = prevWord + word\n        prevWord = ''\n        prevType = ''\n      }\n\n      // すでに文字が入っている上で助詞が続く場合は結合する\n      if (result.length > 0 && token && prevType === '') {\n        result[result.length - 1] += word;\n        prevType = 'keyword';\n        prevWord = word;\n        return\n      }\n\n      // 単語のあとの文字がひらがななら結合する\n      if (result.length > 1 && token || (prevType === 'keyword' && word.match(/[ぁ-んゝ]+/g))) {\n        result[result.length - 1] += word;\n        prevType = ''\n        prevWord = word;\n        return;\n      }\n      result.push(word);\n      prevType = 'keyword';\n      prevWord = word;\n    });\n\n    return result;\n  }\n\n  function Mikan() {\n    var text = arguments.length <= 0 || arguments[0] === undefined\n      ? ''\n      : arguments[0];\n    var userOption = arguments.length <= 1 || arguments[1] === undefined\n      ? {}\n      : arguments[1];\n\n    var defaultOption = {\n      style: 'display:inline-block',\n      role: 'presentation',\n      className: ''\n    };\n    var option = {};\n    Object.keys(defaultOption).forEach(function(key) {\n      option[key] = (typeof userOption[key] === 'undefined')\n        ? defaultOption[key]\n        : userOption[key];\n    });\n\n    var attr = '';\n    option.style && (attr += \" style=\\\"\" + option.style + \"\\\"\");\n    option.role && (attr += \" role=\\\"\" + option.role + \"\\\"\");\n    option.className && (attr += \" class=\\\"\" + option.className + \"\\\"\");\n\n    var words = SimpleAnalyze(text);\n\n    var html = words.map(function(word) {\n      return '<span' + attr + '>' + word + '</span>'\n    }).join('');\n    return html;\n  }\n  Mikan.split = SimpleAnalyze;\n  return Mikan;\n});\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"mikan.js\",\n  \"version\": \"1.0.14\",\n  \"description\": \"Japanese Line Break Organizer\",\n  \"main\": \"src/mikan.js\",\n  \"types\": \"src/mikan.d.ts\",\n  \"files\": [\n    \"src\"\n  ],\n  \"scripts\": {\n    \"test\": \"ava\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"assert\": \"^1.4.1\",\n    \"ava\": \"^0.19.1\"\n  }\n}"
  },
  {
    "path": "src/mikan.d.ts",
    "content": "declare function SimpleAnalyze(str: string): string[];\ndeclare type IUserOption = {\n  style?: string;\n  role?: string;\n  className?: string;\n};\ndeclare function Mikan(text?: string, userOption?: IUserOption): string;\ndeclare namespace Mikan {\n  var split: typeof SimpleAnalyze;\n}\nexport default Mikan;\n"
  },
  {
    "path": "src/mikan.js",
    "content": "/*! mikan.js v1.0.13 | MIT License | https://github.com/trkbt10/mikan.js/blob/master/LICENSE */\n\n\"use strict\";\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD\n    define([], factory);\n  } else if (typeof exports === 'object') {\n    // commonjs\n    module.exports = factory();\n  } else {\n    // Browser globals\n    root.Mikan = factory();\n  }\n})(this, function () {\n\n  var joshi = /(でなければ|について|かしら|くらい|けれど|なのか|ばかり|ながら|ことよ|こそ|こと|さえ|しか|した|たり|だけ|だに|だの|つつ|ても|てよ|でも|とも|から|など|なり|ので|のに|ほど|まで|もの|やら|より|って|で|と|な|に|ね|の|も|は|ば|へ|や|わ|を|か|が|さ|し|ぞ|て)/g;\n  var numbers = /([0-9０-９零一二三四五六七八九十]+)/;\n  var keywords = /(\\&nbsp;|[a-zA-Z0-9]+\\.[a-z]{2,}|[一-龠々〆ヵヶゝ]+|[ぁ-んゝ]+|[ァ-ヴー]+|[a-zA-Z0-9]+|[ａ-ｚＡ-Ｚ０-９]+)/g;\n  var periods = /([\\.\\,。、！\\!？\\?]+)$/g\n  var units = /(px|point|＄|\\$|€|￥|ノット|ユーロ|ドル|円|里|百|千|万|億|兆|京|㌫|％|\\%|cm|m|km|㌢|㍍|㌖|センチメートル|メートル|キロ|キロメートル|°|度|ℓ|リットル|mℓ|ミリリットル|マイル|フィート)/i;\n  var bracketsBegin = /([〈《「『｢（(\\[【〔〚〖〘❮❬❪❨(<{❲❰｛❴])/g\n  var bracketsEnd = /([〉》」』｣)）\\]】〕〗〙〛}>\\)❩❫❭❯❱❳❵｝])/g\n\n\n\n  function SimpleAnalyze(str) {\n    if (!str) {\n      return [''];\n    }\n    var words = str.split(keywords).reduce(function (prev, word) {\n      return [].concat(prev, word.split(joshi));\n    }, []).reduce(function (prev, word) {\n      return [].concat(prev, word.split(numbers));\n    }, []).reduce(function (prev, word) {\n      return [].concat(prev, word.split(bracketsBegin));\n    }, []).reduce(function (prev, word) {\n      return [].concat(prev, word.split(bracketsEnd));\n    }, []).filter(function (word) {\n      return word;\n    });\n    var result = [];\n    var prevType = '';\n    var prevWord = '';\n    words.forEach(function (word) {\n      var periodToken = word.match(periods);\n      var joshiToken = word.match(joshi);\n      var token = periodToken || joshiToken;\n      if (word.match(numbers)) {\n        result.push(word);\n        prevType = 'number';\n        prevWord = word;\n        return\n      }\n      // 前が数字で、後ろが単位であれば数字と単位を結合する\n      if (word.match(units) && prevType === 'number') {\n        result[result.length - 1] += word;\n        prevType = 'unit';\n        prevWord = word;\n        return\n      }\n      if (word.match(bracketsBegin)) {\n        prevType = 'bracketBegin';\n        prevWord = word;\n        return\n      }\n      if (word.match(bracketsEnd)) {\n        result[result.length - 1] += word;\n        prevType = 'bracketEnd';\n        prevWord = word;\n        return\n      }\n\n      if (prevType === 'bracketBegin') {\n        word = prevWord + word\n        prevWord = ''\n        prevType = ''\n      }\n\n      // すでに文字が入っている上で助詞が続く場合は結合する（[単語][て|を|に|は|など]の形にする）\n      if (result.length > 0 && token && prevType === '') {\n        result[result.length - 1] += word;\n        prevType = 'keyword';\n        prevWord = word;\n        return\n      }\n\n      // 単語のあとの文字がひらがななら結合する\n      if (result.length > 1 && token || (prevType === 'keyword' && !prevWord.match(/^[とのに]$/g) && !prevWord.match(periods) && word.match(/[ぁ-んゝ]+/g))) {\n        result[result.length - 1] += word;\n        if (!joshiToken) prevType = ''\n        prevWord = word;\n        return;\n      }\n      result.push(word);\n      prevType = 'keyword';\n      prevWord = word;\n    });\n\n    return result;\n  }\n\n  function Mikan() {\n    var text = arguments.length <= 0 || arguments[0] === undefined\n      ? ''\n      : arguments[0];\n    var userOption = arguments.length <= 1 || arguments[1] === undefined\n      ? {}\n      : arguments[1];\n\n    var defaultOption = {\n      style: 'display:inline-block',\n      role: 'presentation',\n      className: ''\n    };\n    var option = {};\n    Object.keys(defaultOption).forEach(function (key) {\n      option[key] = (typeof userOption[key] === 'undefined')\n        ? defaultOption[key]\n        : userOption[key];\n    });\n\n    var attr = '';\n    option.style && (attr += \" style=\\\"\" + option.style + \"\\\"\");\n    option.role && (attr += \" role=\\\"\" + option.role + \"\\\"\");\n    option.className && (attr += \" class=\\\"\" + option.className + \"\\\"\");\n\n    var words = SimpleAnalyze(text);\n\n    var html = words.map(function (word) {\n      return '<span' + attr + '>' + word + '</span>'\n    }).join('');\n    return html;\n  }\n  Mikan.split = SimpleAnalyze;\n  return Mikan;\n});\n"
  },
  {
    "path": "test/mikan-test.js",
    "content": "const mikan = require('../src/mikan.js')\nconst test = require('ava')\n\nfunction tagToArray(text = \"\") {\n  return text.split(/<.*?>(.*?)<\\/.*?>/g).filter((word) => word)\n}\n\n\ntest(t => {\n  const source = '常に最新、最高のモバイル。Androidを開発した同じチームから。'\n  const expected = ['常に', '最新、', '最高の', 'モバイル。', 'Androidを', '開発した', '同じ', 'チームから。']\n\n  const queue = mikan.split(source)\n  const result = mikan(source)\n\n  t.deepEqual(queue, expected)\n  t.deepEqual(tagToArray(result), expected)\n  t.truthy(result.indexOf('<span style=\"display:inline-block\" role=\"presentation\">') > -1)\n})\n\ntest(t => {\n  const source = '私は好きにした。君たちも好きにしろ。'\n  const result = mikan(source, { className: 'wbr', style: 'font-weight:bold', role: 'debag' })\n  t.truthy(result.indexOf('class=\"wbr\"') > -1)\n  t.truthy(result.indexOf('style=\"font-weight:bold\"') > -1)\n  t.truthy(result.indexOf('role=\"debag\"') > -1)\n})\n\ntest(t => {\n  const source = 'え、蒲田に！？'\n  const result = mikan(source, { className: '', style: '', role: '' })\n  t.truthy(result.indexOf('class=') <= -1)\n  t.truthy(result.indexOf('style=') <= -1)\n  t.truthy(result.indexOf('role=') <= -1)\n})\n\ntest(t => {\n  const source = '原稿と防災服を用意してくれ'\n  const expected = ['原稿と', '防災服を', '用意してくれ']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\n\ntest(t => {\n  const source = '1192'\n  const expected = ['1192']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\ntest(t => {\n  const source = 'やりたいことのそばにいる'\n  const expected = [\"やりたいことの\", \"そばに\", \"いる\"]\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\n\ntest(t => {\n  const source = 'このmikan.jsというライブラリは、スマートな文字区切りを可能にします。'\n  const expected = ['この', 'mikan.jsと', 'いう', 'ライブラリは、', 'スマートな', '文字区切りを', '可能にします。']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\n\ntest(t => {\n  const source = 'テンプレートを使用しますか、それとも空白の調査から始めますか？'\n  const expected = ['テンプレートを', '使用しますか、', 'それとも', '空白の', '調査から', '始めますか？']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\n\ntest(t => {\n  const source = '「あれ」でもない、「これ」でもない。'\n  const expected = ['「あれ」', 'でもない、', '「これ」', 'でもない。']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\n\ntest(t => {\n  const source = '半角スペース 対応'\n  const expected = ['半角', 'スペース', ' ', '対応']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\n\ntest(t => {\n  const source = ''\n  const expected = ['']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\n\ntest(t => {\n  const source = '\\n'\n  const expected = ['\\n']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n\n})\n\ntest(t => {\n  const source = ' '\n  const expected = [' ']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n\n})"
  },
  {
    "path": "test/numbers-and-units-test.js",
    "content": "const mikan = require('../src/mikan.js')\nconst test = require('ava')\n\n\ntest(t => {\n  const source = '桜の花の落ちるスピード。秒速5センチメートル'\n  const expected = [\n    \"桜の\",\n    \"花の\",\n    \"落ちる\",\n    \"スピード。\",\n    \"秒速\",\n    \"5センチメートル\"\n  ]\n\n  const queue = mikan.split(source)\n  const result = mikan(source)\n\n  t.deepEqual(queue, expected)\n  t.truthy(result.indexOf('<span style=\"display:inline-block\" role=\"presentation\">') > -1)\n})\n\ntest(t => {\n  const source = 'ページの読み込みが 50%加速'\n  const expected = ['ページの', '読み', '込みが', ' ', '50%', '加速']\n  const result = mikan.split(source)\n  t.deepEqual(result, expected)\n})\ntest(t => {\n  const source = '赤道を抜け、嵐を抜け、氷を割り、日本から1万4000キロ'\n  const expected = [\n    \"赤道を\",\n    \"抜け、\",\n    \"嵐を\",\n    \"抜け、\",\n    \"氷を\",\n    \"割り、\",\n    \"日本から\",\n    \"1万\", \"4000キロ\",\n  ]\n\n  const queue = mikan.split(source)\n  const result = mikan(source)\n\n  t.deepEqual(queue, expected)\n  t.truthy(result.indexOf('<span style=\"display:inline-block\" role=\"presentation\">') > -1)\n})\n\ntest(t => {\n  const source = '母をたずねて三千里'\n  const expected = [\n    \"母をたずねて\",\n    \"三千里\",\n  ]\n\n  const queue = mikan.split(source)\n  const result = mikan(source)\n\n  t.deepEqual(queue, expected)\n  t.truthy(result.indexOf('<span style=\"display:inline-block\" role=\"presentation\">') > -1)\n})\n\ntest(t => {\n  const source = 'ヘディング190、高度32000、速度720ノット、なお南下中'\n  const expected = [\n    \"ヘディング\",\n    \"190、\",\n    \"高度\",\n    \"32000、\",\n    \"速度\",\n    \"720ノット、なお\",\n    \"南下中\",\n  ]\n\n  const queue = mikan.split(source)\n  const result = mikan(source)\n\n  t.deepEqual(queue, expected)\n  t.truthy(result.indexOf('<span style=\"display:inline-block\" role=\"presentation\">') > -1)\n})\n"
  }
]