"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLanguageService = exports.getRenamePositions = exports.getImportModulePositions = exports.getIdentifierPositions = exports.PACKAGE_IMPORT = void 0;
// tslint:disable-next-line:no-implicit-dependencies
const ts = require("typescript");
exports.PACKAGE_IMPORT = 'igniteui-angular';
/** Returns an source file */
// export function getFileSource(sourceText: string): ts.SourceFile {
//     return ts.createSourceFile('', sourceText, ts.ScriptTarget.Latest, true);
// }
function getIdentifierPositions(sourceText, name) {
    const source = ts.createSourceFile('', sourceText, ts.ScriptTarget.Latest, true);
    const positions = [];
    const checkIdentifier = (node) => {
        if (node.kind !== ts.SyntaxKind.Identifier || !node.parent) {
            return false;
        }
        if (node.parent.kind === ts.SyntaxKind.PropertyDeclaration) {
            return false;
        }
        if (node.parent.kind === ts.SyntaxKind.PropertyAssignment ||
            node.parent.kind === ts.SyntaxKind.PropertySignature) {
            // make sure it's not prop assign  `= { IgxClass: "fake"}`
            //                  definition `prop: { IgxClass: string; }`
            //                                     name: initializer
            const propAssign = node.parent;
            if (propAssign.name.getText() === name) {
                return false;
            }
        }
        return node.text === name;
    };
    const findIdentifiers = (node) => {
        if (checkIdentifier(node)) {
            // Use `.getStart()` as node.pos includes the space(s) before the identifier text
            positions.push({ start: node.getStart(), end: node.end });
        }
        ts.forEachChild(node, findIdentifiers);
    };
    source.forEachChild(findIdentifiers);
    return positions;
}
exports.getIdentifierPositions = getIdentifierPositions;
/** Returns the positions of import from module string literals  */
function getImportModulePositions(sourceText, startsWith) {
    const source = ts.createSourceFile('', sourceText, ts.ScriptTarget.Latest, true);
    const positions = [];
    for (const statement of source.statements) {
        if (statement.kind === ts.SyntaxKind.ImportDeclaration) {
            const specifier = statement.moduleSpecifier;
            if (specifier.text.startsWith(startsWith)) {
                // string literal pos will include quotes, trim with 1
                positions.push({ start: specifier.getStart() + 1, end: specifier.end - 1 });
            }
        }
    }
    return positions;
}
exports.getImportModulePositions = getImportModulePositions;
/** Filters out statements to named imports (e.g. `import {x, y}`) from PACKAGE_IMPORT */
const namedImportFilter = (statement) => {
    if (statement.kind === ts.SyntaxKind.ImportDeclaration &&
        statement.moduleSpecifier.text === exports.PACKAGE_IMPORT) {
        const clause = statement.importClause;
        return clause && clause.namedBindings && clause.namedBindings.kind === ts.SyntaxKind.NamedImports;
    }
    return false;
};
function getRenamePositions(sourcePath, name, service) {
    const source = service.getProgram().getSourceFile(sourcePath);
    const positions = [];
    const imports = source.statements.filter(namedImportFilter);
    if (!imports.length) {
        return positions;
    }
    const elements = imports
        .map(x => x.importClause.namedBindings.elements)
        .reduce((prev, current) => prev.concat(current));
    for (const elem of elements) {
        if (elem.propertyName && elem.propertyName.text === name) {
            // alias imports `igxClass as smth` -> <propertyName> as <name>
            // other references are only for the name portion
            positions.push({ start: elem.propertyName.getStart(), end: elem.propertyName.getEnd() });
            break;
        }
        if (!elem.propertyName && elem.name.text === name) {
            const renames = service.findRenameLocations(sourcePath, elem.name.getStart(), false, false, false);
            if (renames) {
                const renamesPos = renames.map(x => ({ start: x.textSpan.start, end: x.textSpan.start + x.textSpan.length }));
                positions.push(...renamesPos);
            }
        }
    }
    return positions;
}
exports.getRenamePositions = getRenamePositions;
//#region Language Service
/**
 * Create a TypeScript language service
 * @param filePaths Paths for files to include for the language service host
 * @param host Virtual FS host
 * @param options Typescript compiler options for the service
 */
function getLanguageService(filePaths, host, options = {}) {
    // https://stackoverflow.com/a/14221483
    const fileVersions = new Map();
    patchHostOverwrite(host, fileVersions);
    const servicesHost = {
        getCompilationSettings: () => options,
        getScriptFileNames: () => filePaths,
        getScriptVersion: fileName => {
            // return host.actions.filter(x => x.path === fileName && x.kind !== 'c').length.toString();
            const version = fileVersions.get(fileName) || 0;
            return version.toString();
        },
        getScriptSnapshot: fileName => {
            if (!host.exists(fileName)) {
                return undefined;
            }
            return ts.ScriptSnapshot.fromString(host.read(fileName).toString());
        },
        getCurrentDirectory: () => process.cwd(),
        getDefaultLibFileName: opts => ts.getDefaultLibFilePath(opts),
        fileExists: fileName => {
            return filePaths.indexOf(fileName) !== -1;
        }
    };
    return ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
}
exports.getLanguageService = getLanguageService;
function patchHostOverwrite(host, fileVersions) {
    const original = host.overwrite;
    host.overwrite = (path, content) => {
        const version = fileVersions.get(path) || 0;
        fileVersions.set(path, version + 1);
        original.call(host, path, content);
    };
}
//#endregion
