#!/usr/bin/env python3
"""
列出一个 AppCenter 应用目录里「当前这版 index.html 实际用得到」的文件（相对路径，一行一个，只列存在的）。

appCenterSync.sh 用它保留上一代：替换目录前，把旧目录里这些文件中新版没有的拷进新目录，
正开着的旧页面懒加载 chunk 时就不会 404。再往前历次手工覆盖堆下来的文件不在这个闭包里，顺带清掉。

闭包算法与 aaden-php-backend scripts/appcenter_artifact.py 的 referenced() 相同，改一边记得改另一边：
index.html 的 src/href → webpack runtime 的 chunk→hash 表 → js/css 文本里的 hash 资源路径。
"""
import os
import re
import sys

ATTR = re.compile(r'''(?:src|href)=["']?([^"'\s>]+)''')
RUNTIME = re.compile(r'(js|css)/"\+\(\{([^}]*)\}\[\w+\]\|\|\w+\)\+"\."\+\{([^}]*)\}')
PAIR = re.compile(r'"?([\w\-]+)"?:"([\w\-]+)"')
ASSET_REF = re.compile(r'(?<![\w\-])((?:js|css|img|fonts|media)/[\w\-.@]+\.[0-9a-f]{8}\.[A-Za-z0-9]+)')
PRECACHE = re.compile(r'precache-manifest\.[0-9a-f]+\.js')


def norm(ref):
    ref = ref.split('?')[0].split('#')[0]
    if re.match(r'^[a-z]+:|^//', ref):
        return None
    while ref.startswith('./'):
        ref = ref[2:]
    return ref.lstrip('/') or None


def read_text(path):
    with open(path, 'rb') as f:
        return f.read().decode('utf-8', 'replace')


def main(root):
    if not os.path.isfile(os.path.join(root, 'index.html')):
        return
    seen, found = set(), []
    queue = [r for r in (norm(m) for m in ATTR.findall(read_text(os.path.join(root, 'index.html')))) if r]
    queue.append('index.html')
    sw = os.path.join(root, 'service-worker.js')
    if os.path.exists(sw):
        queue.append('service-worker.js')
        queue += PRECACHE.findall(read_text(sw))
    while queue:
        ref = queue.pop()
        if ref in seen:
            continue
        seen.add(ref)
        path = os.path.join(root, ref)
        if not os.path.isfile(path):
            continue
        found.append(ref)
        if not ref.endswith(('.js', '.css')):
            continue
        text = read_text(path)
        for kind, names, hashes in RUNTIME.findall(text):
            name_of = dict(PAIR.findall(names))
            for chunk, h in PAIR.findall(hashes):
                queue.append('%s/%s.%s.%s' % (kind, name_of.get(chunk, chunk), h, kind))
        queue += ASSET_REF.findall(text)
    sys.stdout.write(''.join(r + '\n' for r in sorted(found)))


if __name__ == '__main__':
    main(sys.argv[1])
