Skip to content

Commit ecdbb97

Browse files
committed
Migrate custom Sass functions off the deprecated legacy JS API
Rewrite sass-chroma-js.ts and custom-icons.ts (plus their shared sass-assert/sass-convert helpers) to Dart Sass's modern compileStringAsync API, and switch vite.config.ts's scss preprocessor to api: 'modern'. This removes the "legacy-js-api" deprecation warning on every build. Verified the generated ironsworn.css is byte-for-byte identical to the legacy-API build (after rounding RGB channels to match the old getR()/getG()/getB() precision, since the modern API returns exact fractional channel values).
1 parent 31aa2c8 commit ecdbb97

7 files changed

Lines changed: 177 additions & 305 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"eslint-config-prettier": "^8.8.0",
4545
"eslint-config-standard-with-typescript": "^43",
4646
"eslint-plugin-vue": "^9.25.0",
47+
"immutable": "^5.0.2",
4748
"less": "^4.2.0",
4849
"lodash-es": "^4.17.21",
4950
"marked": "^5.1.0",

pnpm-lock.yaml

Lines changed: 9 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/module/plugin/custom-icons.ts

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { readdirSync } from 'fs'
22
import path from 'path'
33

4-
import type { LegacySyncFunction as SassSyncFunction } from 'sass'
5-
import * as Sass from 'sass'
4+
import type { CustomFunction } from 'sass'
5+
import { SassString } from 'sass'
66
import { assertString } from './sass-assert'
77
import { map2SassMap } from './sass-convert'
88

@@ -17,46 +17,38 @@ function loadIcons(dirString: string) {
1717
return files
1818
}
1919

20-
const plugin: Record<string, SassSyncFunction> = {
21-
// @ts-expect-error
22-
'getIconVars($dir, $prefix)': (
23-
dir: Sass.types.String = new Sass.types.String('system/assets/icons'),
24-
prefix: Sass.types.String = new Sass.types.String('isicon')
25-
) => {
26-
assertString(dir as any)
27-
const dirString = dir.getValue()
20+
const plugin: Record<string, CustomFunction<'sync'>> = {
21+
'getIconVars($dir, $prefix)': ([dir, prefix]) => {
22+
const dirString = assertString(dir).text || 'system/assets/icons'
23+
const prefixValue = assertString(prefix).text || 'isicon'
2824
const files = loadIcons(dirString)
2925
const map = new Map(
3026
files.map((file) => [
31-
`--${prefix.getValue()}-${path.basename(file, '.svg')}`,
27+
`--${prefixValue}-${path.basename(file, '.svg')}`,
3228
file
3329
])
3430
)
3531
return map2SassMap(map, (key, value) => ({
36-
key: new Sass.types.String(key),
37-
value: new Sass.types.String(value)
32+
key: new SassString(key),
33+
value: new SassString(value)
3834
}))
3935
},
40-
// @ts-expect-error
41-
'getIconClasses($dir, $prefix)': (
42-
dir: Sass.types.String = new Sass.types.String('system/assets/icons'),
43-
prefix: Sass.types.String = new Sass.types.String('isicon')
44-
) => {
45-
assertString(dir as any)
46-
const dirString = dir.getValue()
36+
'getIconClasses($dir, $prefix)': ([dir, prefix]) => {
37+
const dirString = assertString(dir).text || 'system/assets/icons'
38+
const prefixValue = assertString(prefix).text || 'isicon'
4739
const files = loadIcons(dirString)
4840
const map = new Map(
4941
files.map((file) => [
50-
`.${prefix.getValue()}-${path.basename(
42+
`.${prefixValue}-${path.basename(
5143
file,
5244
'.svg'
53-
)}, .${prefix.getValue()}bg-${path.basename(file, '.svg')}`,
54-
`--${prefix.getValue()}-${path.basename(file, '.svg')}`
45+
)}, .${prefixValue}bg-${path.basename(file, '.svg')}`,
46+
`--${prefixValue}-${path.basename(file, '.svg')}`
5547
])
5648
)
5749
return map2SassMap(map, (key, value) => ({
58-
key: new Sass.types.String(key),
59-
value: new Sass.types.String(value)
50+
key: new SassString(key),
51+
value: new SassString(value)
6052
}))
6153
}
6254
}

src/module/plugin/sass-assert.ts

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
import type { InterpolationMode } from 'chroma-js'
2-
import type chroma from 'chroma-js'
3-
import * as Sass from 'sass'
2+
import type { Value } from 'sass'
43

5-
// Hack because the sass types package appears to be incorrect.
6-
export type SassLegacyValue<T extends Sass.LegacyValue> = T & {
7-
dartValue: any
8-
getValue: () => any
9-
}
10-
11-
const COLOR_MODES: chroma.InterpolationMode[] = [
4+
const COLOR_MODES: InterpolationMode[] = [
125
'rgb',
136
'hsl',
147
'hsv',
@@ -20,47 +13,45 @@ const COLOR_MODES: chroma.InterpolationMode[] = [
2013
'oklab',
2114
'oklch'
2215
]
16+
2317
// HELPER FUNCTIONS: TYPECHECK SASS VALUES
24-
export function assertColor(obj: SassLegacyValue<Sass.types.Color>) {
25-
if (!(obj instanceof Sass.types.Color)) {
26-
throw new Sass.types.Error(`Expected SASS Color, received: ${obj}`)
27-
}
18+
19+
export function assertColor(obj: Value) {
20+
return obj.assertColor()
2821
}
29-
export function assertNumber(obj: SassLegacyValue<Sass.types.Number>) {
30-
if (!(obj instanceof Sass.types.Number)) {
31-
throw new Sass.types.Error(`Expected SASS Number, received: ${obj}`)
32-
}
22+
export function assertNumber(obj: Value) {
23+
return obj.assertNumber()
3324
}
34-
export function assertList(obj: SassLegacyValue<Sass.types.List>) {
35-
if (!(obj instanceof Sass.types.List)) {
36-
throw new Sass.types.Error(`Expected SASS List, received: ${obj}`)
37-
}
25+
export function assertList(obj: Value) {
26+
// Every Sass value can be used as a list (see `Value.asList`), so there's
27+
// nothing to assert here — this just documents intent at call sites.
28+
return obj
3829
}
39-
export function assertString(obj: SassLegacyValue<Sass.types.String>) {
40-
if (!(obj instanceof Sass.types.String)) {
41-
throw new Sass.types.Error(`Expected SASS String, received: ${obj}`)
42-
}
30+
export function assertString(obj: Value) {
31+
return obj.assertString()
4332
}
44-
export function assertMode(obj: SassLegacyValue<Sass.types.String>) {
45-
assertString(obj)
46-
if (!COLOR_MODES.includes(obj?.getValue() as InterpolationMode)) {
47-
throw new Sass.types.Error(
48-
`Expected a chroma.js color interpolation mode, received: ${obj}`
33+
export function assertMode(obj: Value): string {
34+
const mode = assertString(obj).text
35+
if (!COLOR_MODES.includes(mode as InterpolationMode)) {
36+
throw new Error(
37+
`Expected a chroma.js color interpolation mode, received: ${mode}`
4938
)
5039
}
40+
return mode
5141
}
52-
export function assertModeChannel(obj: SassLegacyValue<Sass.types.String>) {
53-
assertString(obj)
54-
const [mode, chan] = obj.getValue().split('.')
42+
export function assertModeChannel(obj: Value): string {
43+
const value = assertString(obj).text
44+
const [mode, chan] = value.split('.')
5545

5646
if (
5747
// invalid color mode
5848
!COLOR_MODES.includes(mode as InterpolationMode) ||
5949
// invalid color channel for mode. 'a' (alpha channel) is always valid
6050
(chan !== 'a' && !mode.includes(chan))
6151
) {
62-
throw new Sass.types.Error(
63-
`Expected a chroma.js color interpolation mode and channel, received: ${obj}`
52+
throw new Error(
53+
`Expected a chroma.js color interpolation mode and channel, received: ${value}`
6454
)
6555
}
56+
return value
6657
}

0 commit comments

Comments
 (0)