Skip to content

Instantly share code, notes, and snippets.

@lukewestby
Last active July 3, 2017 15:10
Show Gist options
  • Save lukewestby/20afbf900b60602ce73cf7636cde3e33 to your computer and use it in GitHub Desktop.
Save lukewestby/20afbf900b60602ce73cf7636cde3e33 to your computer and use it in GitHub Desktop.
#! 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