← back to digitarhythm__leaf

Function bodies 125 total

All specs Real LLM only Function bodies
load_adsense_script function · javascript · L11-L29 (19 LOC)
adsense.js
export function load_adsense_script() {
    if (is_tauri()) {
        console.log("[AdSense] Tauri environment. Skipping AdSense script load.");
        return;
    }

    if (scriptLoaded) return;

    const script = document.createElement('script');
    script.async = true;
    script.src = `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${ADSENSE_PUB_ID}`;
    script.crossOrigin = 'anonymous';
    script.onerror = () => {
        console.warn("[AdSense] Failed to load AdSense script (ad blocker?).");
    };
    document.head.appendChild(script);
    scriptLoaded = true;
    console.log("[AdSense] Script injected.");
}
render_ad function · javascript · L31-L69 (39 LOC)
adsense.js
export function render_ad(containerId, retryCount = 0) {
    if (is_tauri()) return;

    const MAX_RETRIES = 5;
    const container = document.getElementById(containerId);
    if (!container) {
        console.warn("[AdSense] Container not found:", containerId);
        return;
    }

    // コンテナ幅が0の場合はリトライ(アニメーション中・未レンダリング対策)
    if (container.offsetWidth === 0) {
        if (retryCount < MAX_RETRIES) {
            setTimeout(() => render_ad(containerId, retryCount + 1), 200);
        } else {
            console.warn("[AdSense] Container width is still 0 after retries:", containerId);
        }
        return;
    }

    // Clear existing content
    container.innerHTML = '';

    const ins = document.createElement('ins');
    ins.className = 'adsbygoogle';
    ins.style.cssText = 'display:block;width:100%;';
    ins.setAttribute('data-ad-client', ADSENSE_PUB_ID);
    ins.setAttribute('data-ad-slot', ADSENSE_SLOT_ID);
    ins.setAttribute('data-ad-format', 'auto');
    ins.setAttrib
remove_ad function · javascript · L71-L77 (7 LOC)
adsense.js
export function remove_ad(containerId) {
    const container = document.getElementById(containerId);
    if (container) {
        container.innerHTML = '';
        console.log("[AdSense] Ad removed from:", containerId);
    }
}
exchangeCodeForToken function · javascript · L15-L35 (21 LOC)
auth.js
async function exchangeCodeForToken(code) {
    console.log("[Auth] Exchanging code for tokens via backend...");
    try {
        const response = await fetch('/api/auth/token', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ code })
        });
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            console.error("[Auth] Backend error details:", errorData);
            throw new Error(`Token exchange failed with status ${response.status}`);
        }
        const data = await response.json();
        saveSession(data);
        return data.access_token;
    } catch (e) {
        console.error("[Auth] Exchange error (possibly offline):", e);
        throw e;
    }
}
saveSession function · javascript · L37-L49 (13 LOC)
auth.js
function saveSession(data) {
    accessToken = data.access_token;
    const expiresAt = Date.now() + (parseInt(data.expires_in) * 1000) - (5 * 60 * 1000);

    localStorage.setItem(STORAGE_KEY, accessToken);
    localStorage.setItem(EXPIRY_KEY, expiresAt.toString());
    if (data.refresh_token) {
        localStorage.setItem(REFRESH_TOKEN_KEY, data.refresh_token);
    }

    console.log("Access Token received. Expires at:", new Date(expiresAt));
    window.dispatchEvent(new CustomEvent('leaf-token-refreshed', { detail: accessToken }));
}
init_google_auth function · javascript · L51-L139 (89 LOC)
auth.js
export function init_google_auth(clientId, onSuccessCallback) {
    if (onSuccessCallback) window.onAuthSuccessCallback = onSuccessCallback;
    window.leafClientId = clientId; // Save for parameter passing in later calls

    if (is_tauri()) {
        console.log("[Auth] Tauri environment detected. Using native auth flow.");

        // 既存のトークンがあれば読み込む
        const existingToken = localStorage.getItem(STORAGE_KEY);
        const expiry = localStorage.getItem(EXPIRY_KEY);
        if (existingToken && expiry && parseInt(expiry) > Date.now()) {
            accessToken = existingToken;
            console.log("[Auth-Tauri] Existing valid token found.");
            if (onSuccessCallback) setTimeout(() => onSuccessCallback(accessToken), 0);
        } else if (localStorage.getItem(REFRESH_TOKEN_KEY)) {
            console.log("[Auth-Tauri] Found refresh token. Attempting silent refresh...");
            try_silent_refresh(clientId).then(token => {
                if (token && onSuccessCall
try_silent_refresh function · javascript · L141-L200 (60 LOC)
auth.js
export async function try_silent_refresh(clientId = window.leafClientId) {
    const refreshToken = localStorage.getItem(REFRESH_TOKEN_KEY);
    if (!refreshToken) {
        // リフレッシュトークンがない場合は以前のポップアップ方式へフォールバック
        return force_reauth(clientId);
    }

    if (refreshPromise) return refreshPromise.promise;

    console.log("[Auth] Attempting refresh using refresh_token...");
    let res, rej;
    const promise = new Promise((resolve, reject) => { res = resolve; rej = reject; });
    refreshPromise = { promise, resolve: res, reject: rej };

    if (is_tauri()) {
        // Tauri用のリフレッシュ処理スタブ
        console.log("[Auth-Tauri] Refreshing token via backend...");
        try {
            const token = await window.__TAURI__.core.invoke('refresh_google_token', { refreshToken });
            saveSession({ access_token: token, expires_in: '3600' });
            refreshPromise.resolve(token);
        } catch (e) {
            refreshPromise.reject(e);
            refreshPromise = null;
 
Same scanner, your repo: https://repobility.com — Repobility
request_access_token function · javascript · L202-L214 (13 LOC)
auth.js
export function request_access_token(clientId = window.leafClientId) {
    if (is_tauri()) {
        console.log("[Auth-Tauri] Requesting native access token login flow");
        force_reauth(clientId);
        return;
    }

    if (codeClient) {
        codeClient.requestCode();
    } else {
        console.error("[Auth] codeClient not initialized!");
    }
}
get_access_token function · javascript · L216-L222 (7 LOC)
auth.js
export async function get_access_token(clientId = window.leafClientId) {
    const expiry = localStorage.getItem(EXPIRY_KEY);
    if (expiry && parseInt(expiry) < Date.now()) {
        return await try_silent_refresh(clientId);
    }
    return accessToken;
}
is_signed_in function · javascript · L224-L227 (4 LOC)
auth.js
export function is_signed_in() {
    const expiry = localStorage.getItem(EXPIRY_KEY);
    return (accessToken !== null && expiry && parseInt(expiry) > Date.now()) || !!localStorage.getItem(REFRESH_TOKEN_KEY);
}
fetch_user_email function · javascript · L229-L247 (19 LOC)
auth.js
export async function fetch_user_email() {
    try {
        const token = await get_access_token();
        if (!token) return null;
        const res = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {
            headers: { 'Authorization': `Bearer ${token}` }
        });
        if (!res.ok) throw new Error(`userinfo failed: ${res.status}`);
        const data = await res.json();
        if (data.email) {
            localStorage.setItem('leaf_google_email', data.email);
            console.log("[Auth] User email fetched:", data.email);
        }
        return data.email || null;
    } catch (e) {
        console.warn("[Auth] fetch_user_email failed:", e);
        return null;
    }
}
get_user_email function · javascript · L249-L251 (3 LOC)
auth.js
export function get_user_email() {
    return localStorage.getItem('leaf_google_email') || null;
}
sign_out function · javascript · L253-L268 (16 LOC)
auth.js
export async function sign_out() {
    accessToken = null;
    localStorage.removeItem(STORAGE_KEY);
    localStorage.removeItem(EXPIRY_KEY);
    localStorage.removeItem(REFRESH_TOKEN_KEY);
    localStorage.removeItem('leaf_google_email');
    console.log("Signed out and session cleared");

    if ('serviceWorker' in navigator) {
        try {
            const registrations = await navigator.serviceWorker.getRegistrations();
            for (let registration of registrations) { await registration.unregister(); }
        } catch (e) { console.warn("[Auth] SW unregister failed:", e); }
    }
    window.dispatchEvent(new CustomEvent('leaf-auth-expired'));
}
force_reauth function · javascript · L270-L320 (51 LOC)
auth.js
export async function force_reauth(clientId = window.leafClientId) {
    if (reauthPromise) return reauthPromise.promise;

    console.log("[Auth] Forcing re-authentication...");
    let res, rej;
    const promise = new Promise((resolve, reject) => { res = resolve; rej = reject; });
    reauthPromise = { promise, resolve: res, reject: rej };

    if (is_tauri()) {
        console.log("[Auth-Tauri] Triggering native OAuth login window");
        try {
            if (!clientId) {
                console.error("[Auth-Tauri] CRITICAL: clientId is undefined or null in force_reauth!");
                // Fallback attempt: The Rust backend also has this hardcoded, but we must pass it since it expects it.
                // We'll throw an error if it's genuinely missing so we see it in the console.
                throw new Error("clientId is missing in force_reauth");
            }

            console.log(`[Auth-Tauri] Invoking authenticate_google_force with clientId: ${clientId}`);

     
TauriDatabase class · javascript · L8-L32 (25 LOC)
db.js
class TauriDatabase {
    constructor(path) {
        this.path = path;
    }
    static async load(path) {
        if (!window.__TAURI__) throw new Error("Tauri API not found");
        const _path = await window.__TAURI__.core.invoke('plugin:sql|load', { db: path });
        return new TauriDatabase(_path);
    }
    async execute(query, bindValues) {
        const [rowsAffected, lastInsertId] = await window.__TAURI__.core.invoke('plugin:sql|execute', {
            db: this.path,
            query,
            values: bindValues || []
        });
        return { lastInsertId, rowsAffected };
    }
    async select(query, bindValues) {
        return await window.__TAURI__.core.invoke('plugin:sql|select', {
            db: this.path,
            query,
            values: bindValues || []
        });
    }
}
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
constructor method · javascript · L9-L11 (3 LOC)
db.js
    constructor(path) {
        this.path = path;
    }
load method · javascript · L12-L16 (5 LOC)
db.js
    static async load(path) {
        if (!window.__TAURI__) throw new Error("Tauri API not found");
        const _path = await window.__TAURI__.core.invoke('plugin:sql|load', { db: path });
        return new TauriDatabase(_path);
    }
execute method · javascript · L17-L24 (8 LOC)
db.js
    async execute(query, bindValues) {
        const [rowsAffected, lastInsertId] = await window.__TAURI__.core.invoke('plugin:sql|execute', {
            db: this.path,
            query,
            values: bindValues || []
        });
        return { lastInsertId, rowsAffected };
    }
select method · javascript · L25-L31 (7 LOC)
db.js
    async select(query, bindValues) {
        return await window.__TAURI__.core.invoke('plugin:sql|select', {
            db: this.path,
            query,
            values: bindValues || []
        });
    }
init_db function · javascript · L41-L95 (55 LOC)
db.js
export async function init_db(dbName) {
    if (is_tauri()) {
        console.log("[DB-Tauri] Initializing native database (SQLite)");
        try {
            tauriDb = await TauriDatabase.load('sqlite:leaf.db');
            console.log("SQLite native database loaded.");
            return Promise.resolve();
        } catch (e) {
            console.error("Failed to load native SQLite db:", e);
            return Promise.reject(e);
        }
    }

    // アカウント別DB(LeafDB_xxx)を開く場合、古い「LeafDB」が残っていれば削除
    if (dbName.startsWith('LeafDB_')) {
        try {
            const databases = await indexedDB.databases();
            if (databases.some(d => d.name === 'LeafDB')) {
                indexedDB.deleteDatabase('LeafDB');
                console.log("[DB] Deleted legacy 'LeafDB' database");
            }
        } catch (_) {
            // indexedDB.databases() 非対応ブラウザではスキップ
        }
    }

    return new Promise((resolve, reject) => {
        // バージョンを2に上げる
        const request = 
close_db function · javascript · L97-L102 (6 LOC)
db.js
export function close_db() {
    if (db) {
        db.close();
        db = null;
    }
}
save_sheet function · javascript · L104-L138 (35 LOC)
db.js
export async function save_sheet(sheet) {
    if (is_tauri()) {
        console.log("[DB-Tauri] Saving sheet to native db: ", sheet.id);
        if (!tauriDb) return Promise.reject("Native DB not initialized");
        try {
            await tauriDb.execute(
                "INSERT OR REPLACE INTO sheets (id, title, content, updated_at, folder_id, is_trashed) VALUES ($1, $2, $3, $4, $5, $6)",
                [
                    sheet.id,
                    sheet.title,
                    sheet.content,
                    sheet.updated_at,
                    sheet.folder_id || null, // Ensure valid bind values
                    sheet.is_trashed ? 1 : 0
                ]
            );
            return Promise.resolve();
        } catch (e) {
            console.error("SQLite insert error:", e);
            return Promise.reject(e);
        }
    }

    return new Promise((resolve, reject) => {
        if (!db) {
            reject("DB not initialized");
            return;
  
load_sheets function · javascript · L140-L170 (31 LOC)
db.js
export async function load_sheets() {
    if (is_tauri()) {
        console.log("[DB-Tauri] Loading sheets from native db (SQLite)");
        if (!tauriDb) return Promise.reject("Native DB not initialized");
        try {
            const rows = await tauriDb.select("SELECT * FROM sheets");
            // Normalize columns (SQLite returns numbers where IDB might expect boolean)
            const sheets = rows.map(row => ({
                ...row,
                is_trashed: row.is_trashed === 1
            }));
            return Promise.resolve(sheets);
        } catch (e) {
            console.error("SQLite select error:", e);
            return Promise.reject(e);
        }
    }

    return new Promise((resolve, reject) => {
        if (!db) {
            reject("DB not initialized");
            return;
        }
        const transaction = db.transaction([STORE_SHEETS], "readonly");
        const store = transaction.objectStore(STORE_SHEETS);
        const request = store.getAll(
Repobility · code-quality intelligence · https://repobility.com
delete_sheet function · javascript · L172-L197 (26 LOC)
db.js
export async function delete_sheet(id) {
    if (is_tauri()) {
        console.log("[DB-Tauri] Deleting sheet: ", id);
        if (!tauriDb) return Promise.reject("Native DB not initialized");
        try {
            await tauriDb.execute("DELETE FROM sheets WHERE id = $1", [id]);
            return Promise.resolve();
        } catch (e) {
            console.error("SQLite delete error:", e);
            return Promise.reject(e);
        }
    }

    return new Promise((resolve, reject) => {
        if (!db) {
            reject("DB not initialized");
            return;
        }
        const transaction = db.transaction([STORE_SHEETS], "readwrite");
        const store = transaction.objectStore(STORE_SHEETS);
        const request = store.delete(id);

        request.onsuccess = () => resolve();
        request.onerror = (e) => reject(e.target.error);
    });
}
save_categories function · javascript · L199-L234 (36 LOC)
db.js
export async function save_categories(categories) {
    if (is_tauri()) {
        console.log("[DB-Tauri] Saving categories");
        if (!tauriDb) return Promise.reject("Native DB not initialized");
        try {
            // Transaction-like approach for sync logic: clear and insert
            await tauriDb.execute("DELETE FROM categories");
            for (const cat of categories) {
                await tauriDb.execute(
                    "INSERT INTO categories (id, name, color, sort_order) VALUES ($1, $2, $3, $4)",
                    [cat.id, cat.name, cat.color || null, cat.sort_order || 0]
                );
            }
            return Promise.resolve();
        } catch (e) {
            console.error("SQLite list saving error:", e);
            return Promise.reject(e);
        }
    }

    return new Promise((resolve, reject) => {
        if (!db) { reject("DB not initialized"); return; }
        const transaction = db.transaction([STORE_CATEGORIES], "readwrite");
load_categories function · javascript · L236-L257 (22 LOC)
db.js
export async function load_categories() {
    if (is_tauri()) {
        console.log("[DB-Tauri] Loading categories (SQLite)");
        if (!tauriDb) return Promise.reject("Native DB not initialized");
        try {
            const categories = await tauriDb.select("SELECT * FROM categories ORDER BY sort_order ASC");
            return Promise.resolve(categories);
        } catch (e) {
            console.error("SQLite select error:", e);
            return Promise.reject(e);
        }
    }

    return new Promise((resolve, reject) => {
        if (!db) { reject("DB not initialized"); return; }
        const transaction = db.transaction([STORE_CATEGORIES], "readonly");
        const store = transaction.objectStore(STORE_CATEGORIES);
        const request = store.getAll();
        request.onsuccess = () => resolve(request.result);
        request.onerror = (e) => reject(e.target.error);
    });
}
authenticatedFetch function · javascript · L17-L68 (52 LOC)
drive.js
async function authenticatedFetch(url, options = {}, retryCount = 2) {
    const token = await get_access_token();
    if (!token) {
        throw new Error("UNAUTHORIZED");
    }

    // すでに中断されている場合はリクエストしない
    if (options.signal && options.signal.aborted) {
        throw new Error("AbortError");
    }

    const headers = {
        'Authorization': `Bearer ${token}`,
        ...options.headers
    };

    try {
        const response = await fetch(url, { ...options, headers });

        if (response.status === 401 && retryCount > 0) {
            console.warn("[Drive] 401 Unauthorized. Attempting refresh...");
            try {
                await try_silent_refresh();
                return await authenticatedFetch(url, options, retryCount - 1);
            } catch (e) {
                console.warn("[Drive] Silent refresh failed. Triggering popup re-auth...");
                try {
                    await force_reauth();
                    return await authenticatedFetch(url
list_folders function · javascript · L70-L76 (7 LOC)
drive.js
export async function list_folders(parentId = 'root') {
    const query = `'${parentId}' in parents and mimeType = '${FOLDER_MIME_TYPE}' and trashed=false`;
    const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(query)}&fields=files(id, name)`;
    const response = await authenticatedFetch(url);
    if (!response.ok) throw new Error(`List folders failed: ${response.status}`);
    return await response.json();
}
create_folder function · javascript · L78-L92 (15 LOC)
drive.js
export async function create_folder(folderName, parentId) {
    const createRes = await authenticatedFetch('https://www.googleapis.com/drive/v3/files', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            name: folderName,
            mimeType: FOLDER_MIME_TYPE,
            parents: [parentId]
        })
    });

    if (!createRes.ok) throw new Error(`Create folder failed: ${createRes.status}`);
    const folderData = await createRes.json();
    return folderData.id;
}
find_or_create_folder function · javascript · L94-L119 (26 LOC)
drive.js
export async function find_or_create_folder(folderName, parentId = 'root') {
    const query = `mimeType='${FOLDER_MIME_TYPE}' and name='${folderName}' and '${parentId}' in parents and trashed=false`;
    const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(query)}&fields=files(id, name)`;
    const searchRes = await authenticatedFetch(url);
    
    if (!searchRes.ok) throw new Error(`Search folder failed: ${searchRes.status}`);
    const searchData = await searchRes.json();
    
    if (searchData.files && searchData.files.length > 0) {
        return searchData.files[0].id;
    }
    
    const createRes = await authenticatedFetch('https://www.googleapis.com/drive/v3/files', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            name: folderName,
            mimeType: FOLDER_MIME_TYPE,
            parents: [parentId]
        })
    });

    if (!createRes.ok) throw new Error(`Create folde
ensure_directory_structure function · javascript · L121-L131 (11 LOC)
drive.js
export async function ensure_directory_structure() {
    try {
        const appSupportId = await find_or_create_folder('ApplicationSupport', 'root');
        const leafDataId = await find_or_create_folder('LeafData', appSupportId);
        const othersId = await find_or_create_folder('OTHERS', leafDataId);
        return { appSupportId, leafDataId, othersId };
    } catch (e) {
        console.error("[Drive] Directory structure setup failed:", e);
        throw e;
    }
}
Source: Repobility analyzer · https://repobility.com
buildMultipartBody function · javascript · L133-L146 (14 LOC)
drive.js
function buildMultipartBody(filename, content, folderId, boundary) {
    const encoder = new TextEncoder();
    const metadata = { name: filename, mimeType: FILE_MIME_TYPE };
    if (folderId) metadata.parents = [folderId];

    const part1 = `--${boundary}\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n${JSON.stringify(metadata)}\r\n`;
    const part2 = `--${boundary}\r\nContent-Type: ${FILE_MIME_TYPE}\r\n\r\n`;
    const end = `\r\n--${boundary}--`;

    const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
    
    return new Blob([encoder.encode(part1), encoder.encode(part2), bom, content, encoder.encode(end)], 
                    { type: `multipart/related; boundary=${boundary}` });
}
move_file function · javascript · L148-L153 (6 LOC)
drive.js
export async function move_file(fileId, oldParentId, newParentId) {
    const url = `https://www.googleapis.com/drive/v3/files/${fileId}?addParents=${newParentId}&removeParents=${oldParentId}&fields=id,parents`;
    const response = await authenticatedFetch(url, { method: 'PATCH' });
    if (!response.ok) throw new Error(`Move failed: ${response.status}`);
    return await response.json();
}
rename_folder function · javascript · L155-L164 (10 LOC)
drive.js
export async function rename_folder(folderId, newName) {
    const url = `https://www.googleapis.com/drive/v3/files/${folderId}`;
    const response = await authenticatedFetch(url, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: newName })
    });
    if (!response.ok) throw new Error(`Rename folder failed: ${response.status}`);
    return await response.json();
}
upload_file function · javascript · L166-L191 (26 LOC)
drive.js
export async function upload_file(filename, content, folderId, fileId = null) {
    const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
    const contentWithBom = new Blob([bom, content], { type: FILE_MIME_TYPE });

    if (fileId) {
        const url = `https://www.googleapis.com/upload/drive/v3/files/${fileId}?uploadType=media&fields=id,name,modifiedTime`;
        const response = await authenticatedFetch(url, {
            method: 'PATCH',
            headers: { 'Content-Type': FILE_MIME_TYPE },
            body: contentWithBom
        });

        if (response.ok) return await response.json();
        if (response.status !== 404) throw new Error(`Upload failed: ${response.status}`);
    }

    const boundary = '-------314159265358979323846';
    const body = buildMultipartBody(filename, content, folderId, boundary);
    const response = await authenticatedFetch(`https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id,name,modifiedTime`, {
        method: 'POST',
list_files function · javascript · L193-L199 (7 LOC)
drive.js
export async function list_files(folderId, signal = null) {
    const query = `'${folderId}' in parents and mimeType != '${FOLDER_MIME_TYPE}' and trashed=false`;
    const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(query)}&fields=files(id, name, size, modifiedTime)`;
    const response = await authenticatedFetch(url, { signal });
    if (!response.ok) throw new Error(`List files failed: ${response.status}`);
    return await response.json();
}
delete_file function · javascript · L201-L205 (5 LOC)
drive.js
export async function delete_file(fileId) {
    const response = await authenticatedFetch(`https://www.googleapis.com/drive/v3/files/${fileId}`, { method: 'DELETE' });
    if (!response.ok && response.status !== 404) throw new Error(`Delete failed: ${response.status}`);
    return true;
}
find_file_by_name function · javascript · L207-L214 (8 LOC)
drive.js
export async function find_file_by_name(filename, folderId) {
    const query = `name='${filename.replace(/'/g, "\\'")}' and '${folderId}' in parents and trashed=false`;
    const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(query)}&fields=files(id, name)`;
    const response = await authenticatedFetch(url);
    if (!response.ok) throw new Error(`Find file failed: ${response.status}`);
    const data = await response.json();
    return data.files && data.files.length > 0 ? data.files[0] : null;
}
parse_date function · javascript · L216-L218 (3 LOC)
drive.js
export function parse_date(dateStr) {
    return Date.parse(dateStr);
}
Same scanner, your repo: https://repobility.com — Repobility
download_file function · javascript · L220-L241 (22 LOC)
drive.js
export async function download_file(fileId, range = null, signal = null) {
    try {
        const url = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`;
        const options = { signal };
        if (range) options.headers = { 'Range': `bytes=${range}` };

        const response = await authenticatedFetch(url, options);
        
        if (response.status === 416) return new Uint8Array(0);
        
        if (!response.ok && response.status !== 206) {
            return new Uint8Array(0);
        }

        const buffer = await response.arrayBuffer();
        return new Uint8Array(buffer);
    } catch (e) {
        if (e.name === 'AbortError' || e.message === 'AbortError') return new Uint8Array(0);
        console.error(`[Drive] download_file error for ${fileId}:`, e);
        return new Uint8Array(0);
    }
}
get_file_metadata function · javascript · L243-L248 (6 LOC)
drive.js
export async function get_file_metadata(fileId) {
    const url = `https://www.googleapis.com/drive/v3/files/${fileId}?fields=id,name,size,modifiedTime,trashed,parents`;
    const response = await authenticatedFetch(url);
    if (!response.ok) throw new Error(`Get metadata failed: ${response.status}`);
    return await response.json();
}
getFontSizeKey function · javascript · L11-L14 (4 LOC)
editor_interop.js
function getFontSizeKey() {
    const email = localStorage.getItem('leaf_google_email');
    return email ? `${FONT_SIZE_KEY_BASE}_${email}` : FONT_SIZE_KEY_BASE;
}
can_install_pwa function · javascript · L16-L20 (5 LOC)
editor_interop.js
export function can_install_pwa() {
    const prompt = window.leafDeferredPrompt;
    console.log("[Leaf-PWA] can_install_pwa checked. Status:", !!prompt);
    return !!prompt;
}
is_tauri function · javascript · L22-L24 (3 LOC)
editor_interop.js
export function is_tauri() {
    return !!window.__TAURI__;
}
trigger_pwa_install function · javascript · L26-L37 (12 LOC)
editor_interop.js
export async function trigger_pwa_install() {
    const prompt = window.leafDeferredPrompt;
    if (!prompt) {
        console.warn("[Leaf-PWA] trigger_pwa_install called but prompt is null.");
        return false;
    }
    prompt.prompt();
    const { outcome } = await prompt.userChoice;
    console.log(`[Leaf-PWA] User response to the install prompt: ${outcome}`);
    window.leafDeferredPrompt = null;
    return outcome === 'accepted';
}
is_webkit_or_safari function · javascript · L39-L42 (4 LOC)
editor_interop.js
export function is_webkit_or_safari() {
    const ua = navigator.userAgent.toLowerCase();
    return (ua.indexOf('webkit') !== -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') !== -1);
}
open_local_file function · javascript · L44-L88 (45 LOC)
editor_interop.js
export async function open_local_file() {
    if (is_tauri()) {
        try {
            const result = await window.__TAURI__.core.invoke('open_local_file_native');
            localFileHandle = null; // Tauri ではハンドルは使わない
            localFilePath = result.path; // パスを保持
            return { name: result.name, content: result.content, bytes: new Uint8Array(result.bytes) };
        } catch (e) {
            if (e === 'cancelled') return null;
            console.error("Tauri file open failed:", e);
            return null;
        }
    }
    try {
        const [handle] = await window.showOpenFilePicker({
            types: [{
                description: 'Text Files',
                accept: { 'text/plain': ['.txt', '.md', '.js', '.ts', '.rs', '.toml', '.json', '.yaml', '.yml', '.sql', '.html', '.css', '.py', '.c', '.cpp', '.h', '.m', '.cs', '.php', '.coffee', '.pl', '.rb', '.java', '.sh', '.xml'] }
            }]
        });
        localFileHandle = handle;
        localFilePath =
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
save_local_file function · javascript · L90-L138 (49 LOC)
editor_interop.js
export async function save_local_file(content, needs_bom) {
    if (is_tauri()) {
        try {
            const result = await window.__TAURI__.core.invoke('save_local_file_native', {
                content: content,
                needsBom: needs_bom,
                currentPath: localFilePath || null
            });
            localFilePath = result.path;
            return result.name;
        } catch (e) {
            if (e === 'cancelled') return null;
            console.error("Tauri file save failed:", e);
            return null;
        }
    }
    try {
        // ハンドルがない場合は新規作成ダイアログを表示
        if (!localFileHandle) {
            localFileHandle = await window.showSaveFilePicker({
                suggestedName: 'Untitled.txt',
                types: [{
                    description: 'Text Files',
                    accept: { 'text/plain': ['.txt', '.md', '.js', '.ts', '.rs', '.toml', '.json', '.yaml', '.yml', '.sql', '.html', '.css', '.py', '.c', '.cpp', '.h', '.m', '
clear_local_handle function · javascript · L140-L143 (4 LOC)
editor_interop.js
export function clear_local_handle() {
    localFileHandle = null;
    localFilePath = null;
}
get_safe_chunk function · javascript · L145-L179 (35 LOC)
editor_interop.js
export function get_safe_chunk(uint8array) {
    if (!uint8array || uint8array.length === 0) return { text: "", bytes_consumed: 0 };

    let len = uint8array.length;
    let end = len;

    // UTF-8 のマルチバイト文字が途切れていないかチェック (末尾3バイトを確認)
    for (let i = 1; i <= 3 && i <= len; i++) {
        let byte = uint8array[len - i];
        if ((byte & 0xC0) === 0xC0) { // リーディングバイト (11xxxxxx)
            let expected = 0;
            if ((byte & 0xE0) === 0xC0) expected = 2;      // 2バイト文字
            else if ((byte & 0xF0) === 0xE0) expected = 3; // 3バイト文字
            else if ((byte & 0xF8) === 0xF0) expected = 4; // 4バイト文字

            if (i < expected) {
                // 文字が途切れているので、この文字の直前までで切る
                end = len - i;
            }
            break;
        }
        if ((byte & 0x80) === 0x00) break; // ASCII (0xxxxxxx) なので安全
    }

    // \r\n の途切断チェック (\r で終わっている場合は \n と泣き別れないように1バイト戻す)
    if (end > 0 && uint8array[end - 1] === 0x0D) {
        end--;
    }

    const consumed = u
page 1 / 3next ›