% !Mode:: "TeX:UTF-8:Main"
%needs a fontloader 2017-07-28 or later
%substitutions at word boundaries

\documentclass{article}

\usepackage{luacode,fontspec}
\begin{luacode*}
    fonts.handlers.otf.addfeature {
        name    = "test-a",
        type    = "chainsubstitution",
        lookups = {
            {
                type = "substitution",
                data = {
                    ["a"] = "A",
                    ["b"] = "B",
                    ["c"] = "C",
                    ["d"] = "D",
                },
            },
            {
                type = "ligature",
                data = {
                    ['1'] = { "a", "b" },
                    ['2'] = { "c", "d" },
                },
            },
        },
        data = {
            rules = {
                {
                    before  = { { " ", 0xFFFC } },
                    current = { { "a" }, { "b" } },
                    lookups = { 2 },
                },
                {
                    current = { { "c" }, { "d" } },
                    after   = { { 0xFFFC, " " } },
                    lookups = { 2 },
                },
                {
                    current = { { "a" } },
                    after   = { { "b" } },
                    lookups = { 1 },
                },
                {
                    current = { { "c" } },
                    after   = { { "d" } },
                    lookups = { 1 },
                },
            },
        },
    }

    fonts.handlers.otf.addfeature {
        name    = "test-b",
        type    = "chainsubstitution",
        lookups = {
            {
                type = "ligature",
                data = {
                    ['1'] = { "a", "b" },
                    ['2'] = { "c", "d" },
                },
            },
        },
        data = {
            rules = {
                {
                    -- the space is redundant as 0xFFFC contains it
                    before  = { { " ", 0xFFFC } },
                    current = { { "a" }, { "b" } },
                    lookups = { 1 },
                },
                {
                    current = { { "c" }, { "d" } },
                    -- the space is redundant as 0xFFFC contains it
                    after   = { { 0xFFFC, " " } },
                    lookups = { 1 },
                },
            },
        },
    }

    fonts.handlers.otf.addfeature {
        name    = "test-c",
        type    = "chainsubstitution",
        lookups = {
            {
                type = "ligature",
                data = {
                    ['1'] = { "a", "b" },
                    ['2'] = { "c", "d" },
                },
            },
        },
        data = {
            rules = {
                {
                    before  = { { " " } },
                    current = { { "a" }, { "b" } },
                    lookups = { 1 },
                },
                {
                    current = { { "c" }, { "d" } },
                    after   = { { " " } },
                    lookups = { 1 },
                },
            },
        },
    }
\end{luacode*}


\setmainfont{Arial}[RawFeature=+test-a;]

\begin{document}
Substitutions at word boundaries (spaces):

ab ab abxcd abxcdcdcd

expected output:

1 1 1x2 1xCdCd2

\end{document}