From 44b3e38cc233ecaa85444e0472c82199a74fdf1b 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 (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 --- .github/workflows/csstolua.lua | 132 ++++++++++++++++++ .github/workflows/update-color-primitives.yml | 23 +-- 2 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/csstolua.lua diff --git a/.github/workflows/csstolua.lua b/.github/workflows/csstolua.lua new file mode 100644 index 00000000..01d7ac2d --- /dev/null +++ b/.github/workflows/csstolua.lua @@ -0,0 +1,132 @@ +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('^(.+)%-+(.+)$') + + -- 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 + cur, last = cur[last], 'default' + end + + -- Check duplicates + assert(cur[last] == nil or cur[last] == v) + + 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-color-primitives.yml index f63831d5..59fd7e52 100644 --- a/.github/workflows/update-color-primitives.yml +++ b/.github/workflows/update-color-primitives.yml @@ -2,18 +2,19 @@ name: Get/Update Primer Color 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}/${file%.css}.lua" <