const fs = require('fs');
const path = require('path');

const fileHelpers = require('./file-helpers');
const isDirectory = fileHelpers.isDirectory;
const getFileContents = fileHelpers.getFileContents;
const splitBasename = fileHelpers.splitBasename;

// Allows you to use short words for Roblox Script classes.
//
// Adding '.module' or '.local' between a Lua file's name and extension defines
// it as a ModuleScript or LocalScript, respectively.
//
// word : str
//  This can either be 'module' for ModuleScript, 'local' for LocalScript, or
//  nothing for a plain Script.
function getScriptClassFromWord(word) {
  if (word === 'module') {
    return 'ModuleScript';
  } else if (word === 'local') {
    return 'LocalScript';
  } else {
    return 'Script';
  }
}

// Gets properties of a folder.
//
// Usage:
//
//   getFolderProperties('./Folder/')
//   { Name: 'Folder', ClassName: 'Folder', Children: [ Object... ] }
function getFolderProperties(filePath) {
  const name = path.basename(filePath);

  return {
    Name: name,
    ClassName: 'Folder',
    Children: constructHierarchy(filePath)
  };
}

// Gets properties of a Lua script.
//
// The `ClassName` property varies based on the class identifier (the part after
// the filename). You can see how this works below.
//
// Usage:
//
//   getLuaFileProperties('Server.lua');
//   { Name: 'Server', ClassName: 'Script', Source: '...'}
//
//   getLuaFileProperties('Client.local.lua');
//   { Name: 'Client', ClassName: 'LocalScript', Source: '...'}
//
//   getLuaFileProperties('Helper.module.lua');
//   { Name: 'Helper', ClassName: 'ModuleScript', Source: '...'}
function getLuaFileProperties(filePath) {
  const parts = splitBasename(filePath);

  return {
    Name: parts.name,
    ClassName: getScriptClassFromWord(parts.classIdentifier),
    Source: getFileContents(filePath)
  };
}

// Gets properties for other instances using JSON.
//
// This function allows you to create just about any Roblox instance using JSON
// files. Simply add in-game properties of the instance you're creating and
// they'll appear in-game.
//
// Requirements:
//
// - All properties need to be written in UpperCamelCase.
// - A ClassName property needs to be defined. This lets us know which instance
//   to create.
//
// Usage:
//
//   getJsonFileProperties('/path/to/file.json')
function getJsonFileProperties(filePath) {
  const name = path.basename(filePath, '.json');
  const properties = JSON.parse(getFileContents(filePath));

  properties.Name = name;

  if (!properties.ClassName) {
    console.error('Could not sync ' + filePath + ' (missing ClassName property)');
  };

  return properties;
}

// Simply routes files to the appropriate function for retrieveing properties.
function getFileProperties(filePath) {
  const ext = path.extname(filePath);

  if (ext === '.lua') {
    return getLuaFileProperties(filePath);
  } else if (ext === '.json') {
    return getJsonFileProperties(filePath);
  };
}

// Gets the Roblox properties of a file or folder.
//
// The returned object's keys are in UpperCamelCase, matching Roblox's naming
// convention. This makes it easy to work with the properties when the object is
// passed off to the plugin.
//
// Usage:
//
//   getProperties('./path/to/folder/');
//   { Name: 'folder', ClassName: 'Folder', Children: [ [Object]... ] }
//
//   getProperties('./path/to/file.local.lua');
//   { Name: 'file', ClassName: 'LocalScript', Source: '...'}
function getProperties(filePath) {
  if (isDirectory(filePath)) {
    return getFolderProperties(filePath);
  } else {
    return getFileProperties(filePath);
  };
}

// Gets children and converts them to their appropriate Object.
//
// This is the primary interface to constructing the Object hierarchy. When
// supplied with a folder, it will recursively gather all of that folder's
// children, converting them to their appropriate Object.
//
// When supplied with a file, this just works like getObjectFromFile() or
// newScript().
function constructHierarchy(filePath) {
  const children = [];

  for (const child of fs.readdirSync(filePath)) {
    const childPath = path.join(filePath, child);
    const object = getProperties(childPath);

    if (object) {
      children.push(object);
    };
  };

  return children;
}

module.exports = constructHierarchy

@@ -198,57 +198,8 @@
 nts;
-%0Aconst splitBasename = fileHelpers.splitBasename;
 %0A%0A//
@@ -532,32 +532,33 @@
 tion get
-ScriptClassFromW
+ClassNameFromKeyw
 ord(word
@@ -674,32 +674,55 @@
 cript';%0A  %7D else
+ if (word === 'script')
  %7B%0A    return 'S
@@ -732,16 +732,520 @@
 pt';%0A  %7D
+ else %7B%0A    return null;%0A  %7D%0A%7D%0A%0Afunction getName(filePath) %7B%0A  const base = path.basename(filePath);%0A  const parts = base.split('.');%0A  return parts%5B0%5D;%0A%7D%0A%0Afunction getClassKeyword(filePath) %7B%0A  const base = path.basename(filePath);%0A  const keyword = base.split('.').slice(-2, -1)%5B0%5D;%0A%0A  if (keyword != getName(filePath)) %7B%0A    return keyword;%0A  %7D else %7B%0A    return 'script';%0A  %7D%0A%7D%0A%0Afunction getClassName(filePath) %7B%0A  const keyword = getClassKeyword(filePath);%0A  return getClassNameFromKeyword(keyword);
 %0A%7D%0A%0A// G
@@ -2145,50 +2145,8 @@
 ) %7B%0A
-  const parts = splitBasename(filePath);%0A%0A
   re
@@ -2166,18 +2166,25 @@
 me: 
-parts.name
+getName(filePath)
 ,%0A  
@@ -2203,49 +2203,26 @@
  get
-ScriptClassFromWord(parts.classIdentifier
+ClassName(filePath
 ),%0A 

Refactor how we get the ClassName for a file