From 04440ef6b51e98e86f430e88bc6b61161381a83e Mon Sep 17 00:00:00 2001 From: Tyler Miller Date: Tue, 2 Jul 2024 01:20:52 -0700 Subject: [PATCH] ci(primitives): transition to new css primitives GitHub no longer distributes primitives in JSON format. Also, the names of the values (i.e. CSS variables) have changed. Most of the new names correspond 1-to-1 with one of the old names. Some colors have also changed slightly (e.g. `fg-default`), but otherwise remain mostly the same. See https://primer.style/foundations/primitives/migrating. Source color primitives from `@primer/primitives/dist/internalCss` instead of `@primer/primitives/dist/css/functional/themes` as only the former directory contains the base colors (scales). Convert new primer css primitives/variables directly to lua in .github/workflows/csstolua.lua (runs in CI). This script generates some debugging info in case an error occurs (which can be found in CI logs). Convert to a nested table structure for idiomatic usage in lua. The primitives table now provides type-hints via lsp, and accessing invalid names at runtime will throw an error. Append `.default` to names/keypaths which are too short and would otherwise collide with existing tables. - `scale` no longer exists, but is still provided (by us) for backwards-compatibility and ergonomics. The new names are in the format of `base.color.red[4]` (for example to access `scale.red[5]`). The values in `scale` are 1-indexed for lua, but the original upstream names (in `base.color.*`) are 0-indexed and left untouched. - `scale.gray` no longer exists, use `scale.neutral` in its place - `*.subtle` variants no longer exist, see the link above for the corresponding replacements --- .github/workflows/csstolua.lua | 145 ++++++++++++++++++ ...r-primitives.yml => update-primitives.yml} | 31 ++-- lua/github-theme/group/modules/treesitter.lua | 2 +- lua/github-theme/palette/github_dark.lua | 60 ++++---- .../palette/github_dark_colorblind.lua | 66 ++++---- .../palette/github_dark_default.lua | 54 ++++--- .../palette/github_dark_dimmed.lua | 58 ++++--- .../palette/github_dark_high_contrast.lua | 62 ++++---- .../palette/github_dark_tritanopia.lua | 58 ++++--- lua/github-theme/palette/github_light.lua | 60 ++++---- .../palette/github_light_colorblind.lua | 68 ++++---- .../palette/github_light_default.lua | 60 ++++---- .../palette/github_light_high_contrast.lua | 60 ++++---- .../palette/github_light_tritanopia.lua | 62 ++++---- 14 files changed, 489 insertions(+), 357 deletions(-) create mode 100644 .github/workflows/csstolua.lua rename .github/workflows/{update-color-primitives.yml => update-primitives.yml} (67%) diff --git a/.github/workflows/csstolua.lua b/.github/workflows/csstolua.lua new file mode 100644 index 00000000..485699f7 --- /dev/null +++ b/.github/workflows/csstolua.lua @@ -0,0 +1,145 @@ +local res = {} + +local function is_valid_ident(ident) + local keyword = { + ['do'] = true, + ['end'] = true, + ['if'] = true, + ['then'] = true, + ['local'] = true, + ['function'] = true, + ['return'] = true, + ['while'] = true, + ['repeat'] = true, + ['until'] = true, + ['for'] = true, + ['in'] = true, + ['true'] = true, + ['false'] = true, + ['nil'] = true, + } + + if type(ident) ~= 'string' or keyword[ident] then + return false + end + + return ident:find('^[_%a][_%w]*$') ~= nil +end + +local function set(cssvar, v) + local before, last = cssvar:match('^(.+)%-+(.+)$') + print(('\ncss variable: %s'):format(cssvar)) + print(('css variable prefix: %s'):format(before)) + print(('css variable suffix: %s'):format(last)) + print(('css variable value: %s'):format(v)) + + -- Top-level key + if not last then + res[tonumber(cssvar) or cssvar] = v + return + end + + last = tonumber(last) or last + local cur = res + for k in before:gmatch('[^%-_]+') do + k = tonumber(k) or k + cur[k] = cur[k] or {} + cur = cur[k] + end + + -- Path is too short: append `default` + if type(cur[last]) == 'table' then + local suffix = 'default' + print(('keypath is too short, appending suffix "%s"'):format(suffix)) + print(('new name: %s-%s'):format(cssvar, suffix)) + cur, last = cur[last], suffix + end + + -- Check that duplicates have the same value + if cur[last] ~= nil and cur[last] ~= v then + error(([[ +variable appears multiple times with different values: + - %s + - %s +]]):format(cur[last], v)) + end + + cur[last] = v +end + +local function print_recur(value, _ind) + _ind = _ind or 0 + + if type(value) == 'table' then + io.write('m {') + _ind = _ind + 2 + + for k, v in pairs(value) do + local fmt = '[%q] = ' + if type(k) == 'number' then + fmt = '[%s] = ' + elseif is_valid_ident(k) then + fmt = '%s = ' + end + io.write(('\n%s' .. fmt):format((' '):rep(_ind), k)) + print_recur(v, _ind) + io.write(',') + end + + _ind = _ind - 2 + io.write(('\n%s}'):format((' '):rep(_ind))) + else + io.write(('%q'):format(value)) + end +end + +local defs = {} +for ln in io.lines() do + local k, v = ln:match('^%s*%-%-(%w.-)%s*:%s*(.-)%s*;%s*$') + if k then + table.insert(defs, { k, v }) + end +end + +-- Since we are un-flattening, ensure that longer keys (whose prefix could +-- match another key) are visited first. +table.sort(defs, function(a, b) + return a[1] > b[1] +end) + +for _, kv in ipairs(defs) do + set(unpack(kv)) +end + +-- Add `scale` key for convenience and backwards-compatibility +assert(res.scale == nil) +res.scale = {} +for color, scale in pairs(res.base.color) do + if type(scale) == 'table' then + res.scale[color] = {} + for i, v in pairs(scale) do + res.scale[color][i + 1] = v + end + else + res.scale[color] = scale + end +end + +-- NOTE: the metatable `mt` helps to catch errors (e.g. during CI tests) +io.write([=[ +local mt = { + __index = function(_, k) + error('invalid index: ' .. k) + end, +} +---@generic T +---@param tbl T +---@return T +local function m(tbl) + return setmetatable(tbl, mt) +end +local M = ]=]) + +print_recur(res) + +io.write('\n') diff --git a/.github/workflows/update-color-primitives.yml b/.github/workflows/update-primitives.yml similarity index 67% rename from .github/workflows/update-color-primitives.yml rename to .github/workflows/update-primitives.yml index f63831d5..c6c3eaac 100644 --- a/.github/workflows/update-color-primitives.yml +++ b/.github/workflows/update-primitives.yml @@ -1,19 +1,20 @@ -name: Get/Update Primer Color Primitives +name: Get/Update Primer Primitives env: _DEST_DIR: "${{ github.workspace }}/lua/github-theme/palette/primitives" - _JSON_DIR: "${{ github.workspace }}/node_modules/@primer/primitives/dist/json/colors" + _SRC_DIR: "${{ github.workspace }}/node_modules/@primer/primitives/dist/internalCss" _LICENSE_GLOB: "${{ github.workspace }}/node_modules/@primer/primitives/[Ll][Ii][Cc][Ee][Nn][Ss][Ee]*" _PRIMITIVES_PKGJSON: "${{ github.workspace }}/node_modules/@primer/primitives/package.json" + _CSSTOLUA: "${{ github.workspace }}/.github/workflows/csstolua.lua" on: workflow_dispatch: schedule: - # 3x per week (every other day) at 12:40pm Pacific Time - - cron: "40 19 * * 1,3,5" + # once a week, every Monday at 12:40pm Pacific Time + - cron: "40 19 * * 1" jobs: - get-colors: + install-primitives: runs-on: ubuntu-latest permissions: checks: write @@ -25,6 +26,9 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true - uses: actions/setup-node@v4 with: @@ -34,21 +38,22 @@ jobs: - run: npm i @primer/primitives@latest - run: | - set -u +f + set -eu +f shopt -s nocaseglob failglob license="$(<$_LICENSE_GLOB)" rm -r "$_DEST_DIR" || : mkdir -p "$_DEST_DIR" - cd "$_JSON_DIR" + cd "$_SRC_DIR" if jq -e .version "$_PRIMITIVES_PKGJSON"; then version="M._VERSION = vim.json.decode([=[$(jq -e .version "$_PRIMITIVES_PKGJSON")]=], { luanil = { object = false, array = false } })" fi - for file in *.json; do - cat >|"${_DEST_DIR}/${file%.json}.lua" <| "${_DEST_DIR}/$(tr '-' '_' <<< "${file%.css}.lua")" <