Last active
July 3, 2017 15:10
-
-
Save lukewestby/20afbf900b60602ce73cf7636cde3e33 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! env/bin/python | |
import subprocess | |
import json | |
from typing import Any, Optional, List, TypeVar, Tuple, Callable, Set | |
import os | |
import sys | |
T = TypeVar('T') | |
U = TypeVar('U') | |
def cat_optionals(xs: List[Optional[T]]) -> List[T]: | |
return [x for x in xs if x is not None] | |
class ElmValue(object): | |
def __init__(self, signature: str, name: str) -> None: | |
self.signature = signature | |
self.name = name | |
def __repr__(self) -> str: | |
return '<ElmValue ' + self.name + ' : ' + self.signature + '>' | |
@staticmethod | |
def from_json(data: Any) -> Optional['ElmValue']: | |
return ElmValue(data['signature'], data['name']) | |
class ElmModule(object): | |
def __init__(self, module_name: str, types: List[ElmValue]) -> None: | |
self.name = module_name | |
self.types = types | |
def __repr__(self) -> str: | |
return '<ElmModule ' + self.name + '>' | |
def __hash__(self) -> int: | |
return hash(self.name) | |
def __eq__(self, other: Any) -> bool: | |
if not isinstance(other, ElmModule): | |
return False | |
return self.name == other.name | |
def __ne__(self, other: Any) -> bool: | |
return not self.__eq__(other) | |
def file_path(self) -> str: | |
return '/'.join(self.name.split('.')) + '.elm' | |
@staticmethod | |
def from_json(data: Any) -> Optional['ElmModule']: | |
return ElmModule(data['moduleName'], | |
cat_optionals( | |
[ElmValue.from_json(x) for x in data['types']])) | |
def crawl_dependencies(entry: ElmModule, | |
all_modules: List[ElmModule]) -> Set[ElmModule]: | |
depmods: Set[ElmModule] = set() | |
with open('src/' + entry.file_path(), 'r') as file: | |
for line in file.readlines(): | |
if line.startswith('import'): | |
modname = line.lstrip('import ').split('as')[0].rstrip( | |
' ').split('exposing')[0].rstrip().lstrip() | |
for mod in all_modules: | |
if mod.name == modname: | |
depmods.add(mod) | |
for dep in depmods: | |
depmods.update(crawl_dependencies(dep, all_modules)) | |
depmods.add(entry) | |
return depmods | |
def get_modules_and_types(source_path: str) -> List[ElmModule]: | |
result = subprocess.run( | |
['./node_modules/.bin/elm-interface-to-json', '--path', source_path], | |
stdout=subprocess.PIPE) | |
return cat_optionals( | |
[ElmModule.from_json(x) for x in json.loads(result.stdout)]) | |
def find_stylesheet(mod: ElmModule) -> Optional[ElmValue]: | |
for x in mod.types: | |
if x.signature == 'Css.Stylesheet': | |
return x | |
return None | |
def with_stylesheets( | |
modules: List[ElmModule]) -> List[Tuple[ElmModule, ElmValue]]: | |
mapped = [(m, find_stylesheet(m)) for m in modules] | |
filtered = [(m, v) for (m, v) in mapped if v is not None] | |
return filtered | |
def create_elm_css_file( | |
mods_and_vals: List[Tuple[ElmModule, ElmValue]]) -> str: | |
output = '''port module Stylesheets exposing (..) | |
import Css.File exposing (CssFileStructure, CssCompilerProgram) | |
''' | |
output += '\n'.join(['import ' + m.name for (m, v) in mods_and_vals]) | |
output += '\n\n\nport files : CssFileStructure -> Cmd msg\n\n' | |
output += ''' | |
fileStructure : CssFileStructure | |
fileStructure = | |
Css.File.toFileStructure | |
[ ( "index.css", Css.File.compile [ ''' | |
output += ', '.join([m.name + '.' + v.name for (m, v) in mods_and_vals]) | |
output += '] ) ]' | |
output += '\n\n' | |
output += ''' | |
main : CssCompilerProgram | |
main = | |
Css.File.compiler files fileStructure | |
''' | |
return output | |
def write_elm_file(content: str) -> None: | |
if not os.path.exists('elm-stuff/.elm_css_temp'): | |
os.makedirs('elm-stuff/.elm_css_temp') | |
with open('elm-stuff/.elm_css_temp/Stylesheets.elm', 'w') as text_file: | |
text_file.write(content) | |
def run_elm_css() -> None: | |
result = subprocess.run( | |
[ | |
'node_modules/.bin/elm-css', '--output', 'elm-stuff/.elm_css_temp', | |
'elm-stuff/.elm_css_temp/Stylesheets.elm' | |
], | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE) | |
if result.returncode != 0: | |
print(result.stderr, file=sys.stderr) | |
else: | |
with open('elm-stuff/.elm_css_temp/index.css', 'r') as fin: | |
print(fin.read()) | |
def main() -> None: | |
modules = get_modules_and_types('.') | |
entry = [x for x in modules if x.name == 'Main'][0] | |
if entry is None: | |
return | |
depmods = list(crawl_dependencies(entry, modules)) | |
modules_with_stylesheets = with_stylesheets(depmods) | |
elm_file_content = create_elm_css_file(modules_with_stylesheets) | |
write_elm_file(elm_file_content) | |
run_elm_css() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment