chore: enable stricter oxlint rules
This commit is contained in:
parent
99484bcee5
commit
f3649550f2
282
oxlint.json
282
oxlint.json
|
|
@ -1,7 +1,16 @@
|
|||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript", "import", "unicorn", "vue"],
|
||||
"jsPlugins": ["./lint/plugin.js"],
|
||||
"plugins": [
|
||||
"typescript",
|
||||
"import",
|
||||
"unicorn",
|
||||
"vue",
|
||||
"promise",
|
||||
"node"
|
||||
],
|
||||
"jsPlugins": [
|
||||
"./lint/plugin.js"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2024": true
|
||||
|
|
@ -11,7 +20,13 @@
|
|||
"no-console": [
|
||||
"warn",
|
||||
{
|
||||
"allow": ["warn", "error", "debug", "time", "timeEnd"]
|
||||
"allow": [
|
||||
"warn",
|
||||
"error",
|
||||
"debug",
|
||||
"time",
|
||||
"timeEnd"
|
||||
]
|
||||
}
|
||||
],
|
||||
"eqeqeq": [
|
||||
|
|
@ -34,12 +49,22 @@
|
|||
],
|
||||
"patterns": [
|
||||
{
|
||||
"group": ["@/engine/*"],
|
||||
"group": [
|
||||
"@/engine/*"
|
||||
],
|
||||
"message": "Import from @open-pencil/core unless the module adds platform-specific logic.",
|
||||
"allowImportNames": ["loadFont", "listFamilies", "listFonts", "preloadFonts"]
|
||||
"allowImportNames": [
|
||||
"loadFont",
|
||||
"listFamilies",
|
||||
"listFonts",
|
||||
"preloadFonts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": ["../../packages/*", "../../../packages/*"],
|
||||
"group": [
|
||||
"../../packages/*",
|
||||
"../../../packages/*"
|
||||
],
|
||||
"message": "Use the workspace package name (e.g. @open-pencil/core) instead of relative paths to packages/."
|
||||
}
|
||||
]
|
||||
|
|
@ -97,7 +122,12 @@
|
|||
"vue/define-emits-declaration": "error",
|
||||
"vue/define-props-declaration": "error",
|
||||
"vue/define-props-destructuring": "error",
|
||||
"vue/max-props": ["error", { "maxProps": 16 }],
|
||||
"vue/max-props": [
|
||||
"error",
|
||||
{
|
||||
"maxProps": 16
|
||||
}
|
||||
],
|
||||
"vue/require-default-export": "error",
|
||||
"vue/require-typed-ref": "error",
|
||||
"open-pencil/no-inline-named-types": [
|
||||
|
|
@ -136,7 +166,6 @@
|
|||
"open-pencil/no-broad-double-cast": "error",
|
||||
"open-pencil/no-unknown-record-double-cast": "error",
|
||||
"open-pencil/no-ts-suppression-comments": "error",
|
||||
"open-pencil/no-function-type": "error",
|
||||
"open-pencil/no-reflect-delete-global-this-outside-tests": "error",
|
||||
"open-pencil/no-core-browser-globals": "error",
|
||||
"open-pencil/no-direct-open-pencil-window-internals": "error",
|
||||
|
|
@ -169,17 +198,216 @@
|
|||
"open-pencil/no-component-root-sibling-folder": "error",
|
||||
"open-pencil/no-flat-kiwi-modules": "error",
|
||||
"open-pencil/no-top-level-prefixed-test-files": "error",
|
||||
"open-pencil/no-sibling-domain-prefixed-files": "error"
|
||||
"open-pencil/no-sibling-domain-prefixed-files": "error",
|
||||
"array-callback-return": "error",
|
||||
"block-scoped-var": "error",
|
||||
"default-case-last": "error",
|
||||
"default-param-last": "error",
|
||||
"no-array-constructor": "error",
|
||||
"no-case-declarations": "error",
|
||||
"no-caller": "error",
|
||||
"no-constructor-return": "error",
|
||||
"no-else-return": "error",
|
||||
"no-empty-pattern": "error",
|
||||
"no-eval": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-extra-bind": "error",
|
||||
"no-extra-label": "error",
|
||||
"no-implied-eval": "error",
|
||||
"no-iterator": "error",
|
||||
"no-labels": "error",
|
||||
"no-lone-blocks": "error",
|
||||
"no-multi-str": "error",
|
||||
"no-new": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-object-constructor": "error",
|
||||
"no-proto": "error",
|
||||
"no-return-assign": "error",
|
||||
"no-script-url": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "error",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-unneeded-ternary": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-useless-assignment": "error",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-concat": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"no-useless-rename": "error",
|
||||
"no-useless-return": "error",
|
||||
"prefer-numeric-literals": "error",
|
||||
"prefer-object-has-own": "error",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"prefer-regex-literals": "error",
|
||||
"prefer-rest-params": "error",
|
||||
"prefer-spread": "error",
|
||||
"symbol-description": "error",
|
||||
"unicode-bom": "error",
|
||||
"yoda": "error",
|
||||
"typescript/adjacent-overload-signatures": "error",
|
||||
"typescript/await-thenable": "error",
|
||||
"typescript/ban-ts-comment": "error",
|
||||
"typescript/ban-tslint-comment": "error",
|
||||
"typescript/no-array-delete": "error",
|
||||
"typescript/no-base-to-string": "error",
|
||||
"typescript/no-confusing-non-null-assertion": "error",
|
||||
"typescript/no-duplicate-enum-values": "error",
|
||||
"typescript/no-duplicate-type-constituents": "error",
|
||||
"typescript/no-extraneous-class": "error",
|
||||
"typescript/no-extra-non-null-assertion": "error",
|
||||
"typescript/no-for-in-array": "error",
|
||||
"typescript/no-implied-eval": "error",
|
||||
"typescript/no-invalid-void-type": "error",
|
||||
"typescript/no-meaningless-void-operator": "error",
|
||||
"typescript/no-misused-new": "error",
|
||||
"typescript/no-misused-spread": "error",
|
||||
"typescript/no-mixed-enums": "error",
|
||||
"typescript/no-non-null-asserted-nullish-coalescing": "error",
|
||||
"typescript/no-non-null-asserted-optional-chain": "error",
|
||||
"typescript/no-redundant-type-constituents": "error",
|
||||
"typescript/no-this-alias": "error",
|
||||
"typescript/no-unnecessary-parameter-property-assignment": "error",
|
||||
"typescript/no-unnecessary-qualifier": "error",
|
||||
"typescript/no-unnecessary-type-constraint": "error",
|
||||
"typescript/no-unsafe-enum-comparison": "error",
|
||||
"typescript/no-unsafe-function-type": "error",
|
||||
"typescript/no-unsafe-unary-minus": "error",
|
||||
"typescript/no-useless-default-assignment": "error",
|
||||
"typescript/no-useless-empty-export": "error",
|
||||
"typescript/no-var-requires": "error",
|
||||
"typescript/no-wrapper-object-types": "error",
|
||||
"typescript/only-throw-error": "error",
|
||||
"typescript/prefer-as-const": "error",
|
||||
"typescript/prefer-find": "error",
|
||||
"typescript/prefer-function-type": "error",
|
||||
"typescript/prefer-promise-reject-errors": "error",
|
||||
"typescript/prefer-reduce-type-parameter": "error",
|
||||
"typescript/prefer-return-this-type": "error",
|
||||
"typescript/prefer-ts-expect-error": "error",
|
||||
"typescript/require-array-sort-compare": "error",
|
||||
"typescript/triple-slash-reference": "error",
|
||||
"import/no-absolute-path": "error",
|
||||
"import/no-amd": "error",
|
||||
"import/no-commonjs": "error",
|
||||
"import/no-dynamic-require": "error",
|
||||
"import/no-empty-named-blocks": "error",
|
||||
"import/no-webpack-loader-syntax": "error",
|
||||
"promise/no-callback-in-promise": "error",
|
||||
"promise/no-multiple-resolved": "error",
|
||||
"promise/no-new-statics": "error",
|
||||
"promise/no-promise-in-callback": "error",
|
||||
"promise/no-return-in-finally": "error",
|
||||
"promise/no-return-wrap": "error",
|
||||
"promise/valid-params": "error",
|
||||
"node/no-exports-assign": "error",
|
||||
"node/no-new-require": "error",
|
||||
"node/no-path-concat": "error",
|
||||
"oxc/approx-constant": "error",
|
||||
"oxc/missing-throw": "error",
|
||||
"oxc/no-accumulating-spread": "error",
|
||||
"oxc/no-async-endpoint-handlers": "error",
|
||||
"oxc/no-map-spread": "error",
|
||||
"oxc/number-arg-out-of-range": "error",
|
||||
"oxc/uninvoked-array-callback": "error",
|
||||
"unicorn/consistent-assert": "error",
|
||||
"unicorn/consistent-date-clone": "error",
|
||||
"unicorn/consistent-empty-array-spread": "error",
|
||||
"unicorn/consistent-template-literal-escape": "error",
|
||||
"unicorn/custom-error-definition": "error",
|
||||
"unicorn/error-message": "error",
|
||||
"unicorn/new-for-builtins": "error",
|
||||
"unicorn/no-abusive-eslint-disable": "error",
|
||||
"unicorn/no-accessor-recursion": "error",
|
||||
"unicorn/no-anonymous-default-export": "error",
|
||||
"unicorn/no-array-method-this-argument": "error",
|
||||
"unicorn/no-await-in-promise-methods": "error",
|
||||
"unicorn/no-console-spaces": "error",
|
||||
"unicorn/no-document-cookie": "error",
|
||||
"unicorn/no-empty-file": "error",
|
||||
"unicorn/no-instanceof-builtins": "error",
|
||||
"unicorn/no-invalid-fetch-options": "error",
|
||||
"unicorn/no-invalid-remove-event-listener": "error",
|
||||
"unicorn/no-magic-array-flat-depth": "error",
|
||||
"unicorn/no-negation-in-equality-check": "error",
|
||||
"unicorn/no-new-array": "error",
|
||||
"unicorn/no-new-buffer": "error",
|
||||
"unicorn/no-single-promise-in-promise-methods": "error",
|
||||
"unicorn/no-static-only-class": "error",
|
||||
"unicorn/no-thenable": "error",
|
||||
"unicorn/no-this-assignment": "error",
|
||||
"unicorn/no-unnecessary-array-flat-depth": "error",
|
||||
"unicorn/no-unnecessary-array-splice-count": "error",
|
||||
"unicorn/no-unnecessary-slice-end": "error",
|
||||
"unicorn/no-unreadable-iife": "error",
|
||||
"unicorn/no-useless-collection-argument": "error",
|
||||
"unicorn/no-useless-error-capture-stack-trace": "error",
|
||||
"unicorn/no-useless-iterator-to-array": "error",
|
||||
"unicorn/no-useless-length-check": "error",
|
||||
"unicorn/no-useless-promise-resolve-reject": "error",
|
||||
"unicorn/no-useless-spread": "error",
|
||||
"unicorn/no-useless-switch-case": "error",
|
||||
"unicorn/prefer-array-find": "error",
|
||||
"unicorn/prefer-array-flat": "error",
|
||||
"unicorn/prefer-array-flat-map": "error",
|
||||
"unicorn/prefer-array-index-of": "error",
|
||||
"unicorn/prefer-array-some": "error",
|
||||
"unicorn/prefer-blob-reading-methods": "error",
|
||||
"unicorn/prefer-classlist-toggle": "error",
|
||||
"unicorn/prefer-date-now": "error",
|
||||
"unicorn/prefer-event-target": "error",
|
||||
"unicorn/prefer-keyboard-event-key": "error",
|
||||
"unicorn/prefer-modern-dom-apis": "error",
|
||||
"unicorn/prefer-negative-index": "error",
|
||||
"unicorn/prefer-native-coercion-functions": "error",
|
||||
"unicorn/prefer-object-from-entries": "error",
|
||||
"unicorn/prefer-optional-catch-binding": "error",
|
||||
"unicorn/prefer-prototype-methods": "error",
|
||||
"unicorn/prefer-regexp-test": "error",
|
||||
"unicorn/prefer-set-size": "error",
|
||||
"unicorn/prefer-string-slice": "error",
|
||||
"unicorn/prefer-string-trim-start-end": "error",
|
||||
"unicorn/prefer-structured-clone": "error",
|
||||
"unicorn/prefer-type-error": "error",
|
||||
"unicorn/require-array-join-separator": "error",
|
||||
"unicorn/require-number-to-fixed-digits-argument": "error",
|
||||
"unicorn/throw-new-error": "error",
|
||||
"vue/no-deprecated-data-object-declaration": "error",
|
||||
"vue/no-deprecated-delete-set": "error",
|
||||
"vue/no-deprecated-events-api": "error",
|
||||
"vue/no-deprecated-model-definition": "error",
|
||||
"vue/no-deprecated-vue-config-keycodes": "error",
|
||||
"vue/no-this-in-before-route-enter": "error",
|
||||
"vue/return-in-computed-property": "error",
|
||||
"unicorn/require-post-message-target-origin": "error",
|
||||
"unicorn/prefer-set-has": "error",
|
||||
"unicorn/prefer-modern-math-apis": "error",
|
||||
"unicorn/prefer-node-protocol": "error",
|
||||
"unicorn/prefer-number-properties": "error",
|
||||
"prefer-exponentiation-operator": "error",
|
||||
"no-promise-executor-return": "error",
|
||||
"typescript/no-empty-object-type": "error",
|
||||
"typescript/return-await": "error",
|
||||
"typescript/restrict-plus-operands": "error",
|
||||
"unicorn/prefer-includes": "error",
|
||||
"no-loop-func": "error",
|
||||
"typescript/no-dynamic-delete": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["src/**/*.ts", "packages/*/src/**/*.ts"],
|
||||
"files": [
|
||||
"src/**/*.ts",
|
||||
"packages/*/src/**/*.ts"
|
||||
],
|
||||
"rules": {
|
||||
"open-pencil/no-useless-pass-through-wrappers": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["**/kiwi/kiwi-schema/**"],
|
||||
"files": [
|
||||
"**/kiwi/kiwi-schema/**"
|
||||
],
|
||||
"rules": {
|
||||
"typescript/no-explicit-any": "off",
|
||||
"typescript/no-non-null-assertion": "off",
|
||||
|
|
@ -196,13 +424,18 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"files": ["packages/cli/src/**", "packages/mcp/src/**"],
|
||||
"files": [
|
||||
"packages/cli/src/**",
|
||||
"packages/mcp/src/**"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["packages/cli/src/commands/**"],
|
||||
"files": [
|
||||
"packages/cli/src/commands/**"
|
||||
],
|
||||
"rules": {
|
||||
"open-pencil/no-raw-console-format": "error"
|
||||
}
|
||||
|
|
@ -218,11 +451,30 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"files": ["scripts/**/*.ts"],
|
||||
"files": [
|
||||
"scripts/**/*.ts"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"packages/core/src/io/formats/fig/export.ts",
|
||||
"packages/core/src/kiwi/fig/parse/worker.ts"
|
||||
],
|
||||
"rules": {
|
||||
"unicorn/require-post-message-target-origin": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"ignorePatterns": ["node_modules", "dist", "desktop", "*.config.*"]
|
||||
"ignorePatterns": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"desktop",
|
||||
"*.config.*"
|
||||
],
|
||||
"categories": {
|
||||
"correctness": "error"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import { loadDocument } from '#cli/headless'
|
|||
|
||||
const io = new IORegistry(BUILTIN_IO_FORMATS)
|
||||
const RASTER_FORMATS = ['PNG', 'JPG', 'WEBP']
|
||||
const ALL_FORMATS = [...RASTER_FORMATS, 'SVG', 'PDF', 'JSX', 'FIG']
|
||||
const JSX_STYLES = ['openpencil', 'tailwind']
|
||||
const ALL_FORMATS = new Set([...RASTER_FORMATS, 'SVG', 'PDF', 'JSX', 'FIG'])
|
||||
const JSX_STYLES = new Set(['openpencil', 'tailwind'])
|
||||
|
||||
interface ExportArgs {
|
||||
file?: string
|
||||
|
|
@ -191,12 +191,12 @@ export default defineCommand({
|
|||
},
|
||||
async run({ args }) {
|
||||
const format = args.format.toUpperCase() as RasterExportFormat | 'SVG' | 'JSX' | 'FIG'
|
||||
if (!ALL_FORMATS.includes(format)) {
|
||||
if (!ALL_FORMATS.has(format)) {
|
||||
printError(`Invalid format "${args.format}". Use png, jpg, webp, svg, pdf, jsx, or fig.`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (format === 'JSX' && !JSX_STYLES.includes(args.style)) {
|
||||
if (format === 'JSX' && !JSX_STYLES.has(args.style)) {
|
||||
printError(`Invalid JSX style "${args.style}". Use openpencil or tailwind.`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export function drawFlashes(r: SkiaRenderer, canvas: Canvas, graph: SceneGraph):
|
|||
|
||||
if (elapsed < FLASH_ATTACK_MS) {
|
||||
const t = elapsed / FLASH_ATTACK_MS
|
||||
const ease = t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2
|
||||
const ease = t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2
|
||||
opacity = ease
|
||||
extraPad = (1 - ease) * FLASH_OVERSHOOT
|
||||
} else if (elapsed < FLASH_ATTACK_MS + FLASH_HOLD_MS) {
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ export function drawRulerBadge(
|
|||
export function rulerStep(r: SkiaRenderer): number {
|
||||
const pixelsPerUnit = r.zoom
|
||||
const rawStep = RULER_TARGET_PIXEL_SPACING / pixelsPerUnit
|
||||
const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)))
|
||||
const magnitude = 10 ** Math.floor(Math.log10(rawStep))
|
||||
const normalized = rawStep / magnitude
|
||||
|
||||
if (normalized <= 1) return magnitude
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ function isCulled(r: SkiaRenderer, node: SceneNode, absX: number, absY: number):
|
|||
const bw = node.width
|
||||
const bh = node.height
|
||||
if (node.rotation !== 0) {
|
||||
const diag = Math.sqrt(bw * bw + bh * bh)
|
||||
const diag = Math.hypot(bw, bh)
|
||||
const cx = absX + bw / 2
|
||||
const cy = absY + bh / 2
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -31,6 +31,6 @@ export namespace JSX {
|
|||
}
|
||||
|
||||
export interface ElementChildrenAttribute {
|
||||
children: {}
|
||||
children: unknown
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,12 +181,12 @@ function hasAutoLayoutTriggerProps(props: Record<string, unknown>): boolean {
|
|||
|
||||
function parseTrack(token: string): GridTrack {
|
||||
if (token.endsWith('fr')) {
|
||||
return { sizing: 'FR', value: parseFloat(token) || 1 }
|
||||
return { sizing: 'FR', value: Number.parseFloat(token) || 1 }
|
||||
}
|
||||
if (token === 'auto') {
|
||||
return { sizing: 'AUTO', value: 0 }
|
||||
}
|
||||
return { sizing: 'FIXED', value: parseFloat(token) || 0 }
|
||||
return { sizing: 'FIXED', value: Number.parseFloat(token) || 0 }
|
||||
}
|
||||
|
||||
function parseTrackList(value: string): GridTrack[] {
|
||||
|
|
@ -410,8 +410,8 @@ function applyShapeAndEffectOverrides(props: Record<string, unknown>, o: Partial
|
|||
{
|
||||
type: 'DROP_SHADOW',
|
||||
color: c,
|
||||
offset: { x: parseFloat(parts[0]), y: parseFloat(parts[1]) },
|
||||
radius: parseFloat(parts[2]),
|
||||
offset: { x: Number.parseFloat(parts[0]), y: Number.parseFloat(parts[1]) },
|
||||
radius: Number.parseFloat(parts[2]),
|
||||
spread: 0,
|
||||
visible: true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,8 +77,9 @@ export function createVariantActions(ctx: EditorContext) {
|
|||
for (const childId of node.childIds) {
|
||||
const child = ctx.graph.getNode(childId)
|
||||
if (!child) continue
|
||||
const values = { ...child.componentPropertyValues }
|
||||
delete values[def.name]
|
||||
const values = Object.fromEntries(
|
||||
Object.entries(child.componentPropertyValues).filter(([key]) => key !== def.name)
|
||||
)
|
||||
ctx.graph.updateNode(childId, { componentPropertyValues: values })
|
||||
}
|
||||
ctx.undo.push({
|
||||
|
|
@ -94,8 +95,9 @@ export function createVariantActions(ctx: EditorContext) {
|
|||
for (const cid of n.childIds) {
|
||||
const c = ctx.graph.getNode(cid)
|
||||
if (!c) continue
|
||||
const v = { ...c.componentPropertyValues }
|
||||
delete v[def.name]
|
||||
const v = Object.fromEntries(
|
||||
Object.entries(c.componentPropertyValues).filter(([key]) => key !== def.name)
|
||||
)
|
||||
ctx.graph.updateNode(cid, { componentPropertyValues: v })
|
||||
}
|
||||
}
|
||||
|
|
@ -126,9 +128,11 @@ export function createVariantActions(ctx: EditorContext) {
|
|||
if (!child) continue
|
||||
const values = { ...child.componentPropertyValues }
|
||||
if (prevName in values) {
|
||||
values[newName] = values[prevName]
|
||||
delete values[prevName]
|
||||
ctx.graph.updateNode(childId, { componentPropertyValues: values })
|
||||
const nextValues = Object.fromEntries(
|
||||
Object.entries(values).filter(([key]) => key !== prevName)
|
||||
)
|
||||
nextValues[newName] = values[prevName]
|
||||
ctx.graph.updateNode(childId, { componentPropertyValues: nextValues })
|
||||
}
|
||||
}
|
||||
const renamePropertyDef = (name: string) => {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function attrValue(tag: string, attr: string): string | null {
|
|||
|
||||
function num(tag: string, attr: string, fallback = 0): number {
|
||||
const value = attrValue(tag, attr)
|
||||
return value !== null ? parseFloat(value) : fallback
|
||||
return value !== null ? Number.parseFloat(value) : fallback
|
||||
}
|
||||
|
||||
function shapeToD(tagName: string, tag: string): string | null {
|
||||
|
|
@ -118,7 +118,7 @@ export function extractPaths(svgBody: string): IconPathInfo[] {
|
|||
d,
|
||||
fill: resolveAttr(attrValue(tag, 'fill'), groupAttrs.fill, 'currentColor'),
|
||||
stroke: resolveAttr(attrValue(tag, 'stroke'), groupAttrs.stroke, null),
|
||||
strokeWidth: parseFloat(attrValue(tag, 'stroke-width') ?? groupAttrs.strokeWidth ?? '1'),
|
||||
strokeWidth: Number.parseFloat(attrValue(tag, 'stroke-width') ?? groupAttrs.strokeWidth ?? '1'),
|
||||
strokeCap: attrValue(tag, 'stroke-linecap') ?? groupAttrs.strokeCap ?? 'butt',
|
||||
strokeJoin: attrValue(tag, 'stroke-linejoin') ?? groupAttrs.strokeJoin ?? 'miter',
|
||||
fillRule: fillRuleAttr === 'evenodd' ? 'EVENODD' : 'NONZERO'
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ function createGradientDef(
|
|||
if (fill.type === 'GRADIENT_RADIAL' || fill.type === 'GRADIENT_DIAMOND') {
|
||||
const cx = round(t.m02 * 100)
|
||||
const cy = round(t.m12 * 100)
|
||||
const r = round(Math.sqrt(t.m00 * t.m00 + t.m10 * t.m10) * 100)
|
||||
const r = round(Math.hypot(t.m00, t.m10) * 100)
|
||||
return {
|
||||
id,
|
||||
node: svg(
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ export function encodeMessage(message: FigmaMessage): Uint8Array {
|
|||
const ncHex = Buffer.from(ncBytes).toString('hex')
|
||||
const finalHex = beforeArray + ncHex + afterArray
|
||||
|
||||
const finalBytes = new Uint8Array(finalHex.match(/.{2}/g)?.map((b) => parseInt(b, 16)) ?? [])
|
||||
const finalBytes = new Uint8Array(finalHex.match(/.{2}/g)?.map((b) => Number.parseInt(b, 16)) ?? [])
|
||||
return compress(finalBytes)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ export function parseVariableId(variableId: string): GUID | null {
|
|||
const match = variableId.match(/VariableID:(\d+):(\d+)/)
|
||||
if (!match) return null
|
||||
return {
|
||||
sessionID: parseInt(match[1] ?? '0', 10),
|
||||
localID: parseInt(match[2] ?? '0', 10)
|
||||
sessionID: Number.parseInt(match[1] ?? '0', 10),
|
||||
localID: Number.parseInt(match[2] ?? '0', 10)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ export class ByteBuffer {
|
|||
writeVarUint64(value: bigint | string): void {
|
||||
if (typeof value === 'string') value = BigInt(value)
|
||||
else if (typeof value !== 'bigint')
|
||||
throw new Error('Expected bigint but got ' + typeof value + ': ' + value)
|
||||
throw new Error(`Expected bigint but got ${typeof value}: ${String(value)}`)
|
||||
if (value < 0 || value > BigInt('0xFFFFFFFFFFFFFFFF'))
|
||||
throw new Error('Outside uint64 range: ' + value)
|
||||
let mask = BigInt(127)
|
||||
|
|
@ -202,7 +202,7 @@ export class ByteBuffer {
|
|||
writeVarInt64(value: bigint | string): void {
|
||||
if (typeof value === 'string') value = BigInt(value)
|
||||
else if (typeof value !== 'bigint')
|
||||
throw new Error('Expected bigint but got ' + typeof value + ': ' + value)
|
||||
throw new Error(`Expected bigint but got ${typeof value}: ${String(value)}`)
|
||||
if (value < -BigInt('0x8000000000000000') || value > BigInt('0x7FFFFFFFFFFFFFFF'))
|
||||
throw new Error('Outside int64 range: ' + value)
|
||||
let one = BigInt(1)
|
||||
|
|
|
|||
|
|
@ -191,14 +191,14 @@ function verify(root: Schema): void {
|
|||
// Define definitions
|
||||
for (let i = 0; i < root.definitions.length; i++) {
|
||||
let definition = root.definitions[i]
|
||||
if (definedTypes.indexOf(definition.name) !== -1) {
|
||||
if (definedTypes.includes(definition.name)) {
|
||||
error(
|
||||
'The type ' + quote(definition.name) + ' is defined twice',
|
||||
definition.line,
|
||||
definition.column
|
||||
)
|
||||
}
|
||||
if (reservedNames.indexOf(definition.name) !== -1) {
|
||||
if (reservedNames.includes(definition.name)) {
|
||||
error(
|
||||
'The type name ' + quote(definition.name) + ' is reserved',
|
||||
definition.line,
|
||||
|
|
@ -221,7 +221,7 @@ function verify(root: Schema): void {
|
|||
// Check types
|
||||
for (let j = 0; j < fields.length; j++) {
|
||||
let field = fields[j]
|
||||
if (definedTypes.indexOf(field.type!) === -1) {
|
||||
if (!definedTypes.includes(field.type!)) {
|
||||
error(
|
||||
'The type ' + quote(field.type!) + ' is not defined for field ' + quote(field.name),
|
||||
field.line,
|
||||
|
|
@ -234,7 +234,7 @@ function verify(root: Schema): void {
|
|||
let values: number[] = []
|
||||
for (let j = 0; j < fields.length; j++) {
|
||||
let field = fields[j]
|
||||
if (values.indexOf(field.value) !== -1) {
|
||||
if (values.includes(field.value)) {
|
||||
error('The id for field ' + quote(field.name) + ' is used twice', field.line, field.column)
|
||||
}
|
||||
if (field.value <= 0) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export function guidToString(guid: GUID): string {
|
|||
|
||||
export function stringToGuid(str: string): GUID {
|
||||
const match = str.match(/^(?:VariableID:|VariableCollectionId:)?(\d+):(\d+)$/)
|
||||
if (match) return { sessionID: parseInt(match[1], 10), localID: parseInt(match[2], 10) }
|
||||
if (match) return { sessionID: Number.parseInt(match[1], 10), localID: Number.parseInt(match[2], 10) }
|
||||
const [session, local] = str.split(':')
|
||||
return { sessionID: parseInt(session, 10), localID: parseInt(local, 10) }
|
||||
return { sessionID: Number.parseInt(session, 10), localID: Number.parseInt(local, 10) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { defineRule } from '#core/lint/rule'
|
||||
const SCALE = [0, 2, 4, 6, 8, 12, 16, 20, 24, 32, 9999]
|
||||
const SCALE = new Set([0, 2, 4, 6, 8, 12, 16, 20, 24, 32, 9999])
|
||||
export default defineRule({
|
||||
meta: {
|
||||
id: 'consistent-radius',
|
||||
|
|
@ -8,7 +8,7 @@ export default defineRule({
|
|||
},
|
||||
match: ['RECTANGLE', 'FRAME', 'COMPONENT', 'INSTANCE'],
|
||||
check(node, context) {
|
||||
if (node.cornerRadius > 0 && !SCALE.includes(node.cornerRadius))
|
||||
if (node.cornerRadius > 0 && !SCALE.has(node.cornerRadius))
|
||||
context.report({
|
||||
node,
|
||||
message: `Corner radius ${node.cornerRadius}px is not in scale`,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export class GPUTimer {
|
|||
private ext: EXTDisjointTimerQuery | null = null
|
||||
private pending: WebGLQuery[] = []
|
||||
private activeQuery: WebGLQuery | null = null
|
||||
private _lastGpuTimeMs = NaN
|
||||
private _lastGpuTimeMs = Number.NaN
|
||||
|
||||
get available(): boolean {
|
||||
return this.ext !== null
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ export const analyzeColorsCommand: RpcCommand<AnalyzeColorsArgs, AnalyzeColorsRe
|
|||
|
||||
// ── analyze typography ──
|
||||
|
||||
export interface AnalyzeTypographyArgs {}
|
||||
export type AnalyzeTypographyArgs = Record<string, never>
|
||||
|
||||
export interface TypographyStyle {
|
||||
family: string
|
||||
|
|
|
|||
|
|
@ -14,18 +14,20 @@ function walkNodes(graph: SceneGraph, rootId: string, fn: (node: SceneNode) => b
|
|||
return true
|
||||
}
|
||||
|
||||
function countNodes(graph: SceneGraph, pageId: string): number {
|
||||
function countDescendants(graph: SceneGraph, rootId: string): number {
|
||||
let count = 0
|
||||
const page = graph.getNode(pageId)
|
||||
if (page)
|
||||
for (const cid of page.childIds)
|
||||
walkNodes(graph, cid, () => {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
walkNodes(graph, rootId, () => {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
return count
|
||||
}
|
||||
|
||||
function countNodes(graph: SceneGraph, pageId: string): number {
|
||||
const page = graph.getNode(pageId)
|
||||
return page?.childIds.reduce((count, id) => count + countDescendants(graph, id), 0) ?? 0
|
||||
}
|
||||
|
||||
function nodeFrame(node: SceneNode) {
|
||||
return {
|
||||
x: Math.round(node.x),
|
||||
|
|
@ -54,18 +56,19 @@ export const infoCommand: RpcCommand<void, InfoResult> = {
|
|||
const fonts = new Set<string>()
|
||||
const pageCounts: Record<string, number> = {}
|
||||
|
||||
const countNode = (node: SceneNode) => {
|
||||
totalNodes++
|
||||
types[node.type] = (types[node.type] ?? 0) + 1
|
||||
if (node.fontFamily) fonts.add(node.fontFamily)
|
||||
return true
|
||||
}
|
||||
|
||||
for (const page of pages) {
|
||||
let pageCount = 0
|
||||
const beforePage = totalNodes
|
||||
for (const cid of page.childIds) {
|
||||
walkNodes(graph, cid, (node) => {
|
||||
totalNodes++
|
||||
pageCount++
|
||||
types[node.type] = (types[node.type] ?? 0) + 1
|
||||
if (node.fontFamily) fonts.add(node.fontFamily)
|
||||
return true
|
||||
})
|
||||
walkNodes(graph, cid, countNode)
|
||||
}
|
||||
pageCounts[page.name] = pageCount
|
||||
pageCounts[page.name] = totalNodes - beforePage
|
||||
}
|
||||
|
||||
return { pages: pages.length, totalNodes, types, fonts: [...fonts].sort(), pageCounts }
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ export class SceneGraph {
|
|||
let idx = insertIndex
|
||||
if (
|
||||
oldParent === newParent &&
|
||||
idx > (oldParent.childIds.indexOf(nodeId) === -1 ? idx : oldParent.childIds.length)
|
||||
idx > (!oldParent.childIds.includes(nodeId) ? idx : oldParent.childIds.length)
|
||||
) {
|
||||
// Already removed above, no adjustment needed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ export function removeVariable(graph: SceneGraph, id: string): void {
|
|||
collection.variableIds = collection.variableIds.filter((vid) => vid !== id)
|
||||
}
|
||||
for (const node of graph.nodes.values()) {
|
||||
for (const [field, varId] of Object.entries(node.boundVariables)) {
|
||||
if (varId === id) delete node.boundVariables[field]
|
||||
}
|
||||
node.boundVariables = Object.fromEntries(
|
||||
Object.entries(node.boundVariables).filter(([, varId]) => varId !== id)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +140,11 @@ export function removeMode(graph: SceneGraph, collectionId: string, modeId: stri
|
|||
}
|
||||
for (const varId of collection.variableIds) {
|
||||
const variable = graph.variables.get(varId)
|
||||
if (variable) delete variable.valuesByMode[modeId]
|
||||
if (variable) {
|
||||
variable.valuesByMode = Object.fromEntries(
|
||||
Object.entries(variable.valuesByMode).filter(([id]) => id !== modeId)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (graph.activeMode.get(collectionId) === modeId) {
|
||||
graph.activeMode.set(collectionId, collection.defaultModeId)
|
||||
|
|
@ -232,5 +236,9 @@ export function bindVariable(
|
|||
|
||||
export function unbindVariable(graph: SceneGraph, nodeId: string, field: string): void {
|
||||
const node = graph.nodes.get(nodeId)
|
||||
if (node) delete node.boundVariables[field]
|
||||
if (node) {
|
||||
node.boundVariables = Object.fromEntries(
|
||||
Object.entries(node.boundVariables).filter(([key]) => key !== field)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,8 +49,13 @@ export function removeStyleFromRange(
|
|||
|
||||
for (let i = start; i < end && i < textLength; i++) {
|
||||
if (chars[i]) {
|
||||
const copy = { ...chars[i] }
|
||||
for (const k of keys) delete copy[k]
|
||||
const current = chars[i]
|
||||
if (!current) continue
|
||||
const copy = Object.fromEntries(
|
||||
Object.entries(current).filter(
|
||||
([key]) => !keys.includes(key as keyof CharacterStyleOverride)
|
||||
)
|
||||
) as CharacterStyleOverride
|
||||
chars[i] = Object.keys(copy).length > 0 ? copy : null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ function parseSvgViewBox(svg: string): Rect | null {
|
|||
function parseSvgDimension(svg: string, attr: string): number | null {
|
||||
const match = svg.match(new RegExp(`\\b${attr}="([^"]+)"`))
|
||||
if (!match) return null
|
||||
const n = parseFloat(match[1])
|
||||
const n = Number.parseFloat(match[1])
|
||||
return Number.isFinite(n) && n > 0 ? n : null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ function nearestPointOnLine(px: number, py: number, p0: Vector, p1: Vector): Nea
|
|||
const y = p0.y + t * dy
|
||||
const ddx = x - px
|
||||
const ddy = y - py
|
||||
return { t, x, y, distance: Math.sqrt(ddx * ddx + ddy * ddy) }
|
||||
return { t, x, y, distance: Math.hypot(ddx, ddy) }
|
||||
}
|
||||
|
||||
/** Find nearest point across all segments in a VectorNetwork. */
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { serve } from '@hono/node-server'
|
|||
|
||||
import { startServer } from './server.js'
|
||||
|
||||
const port = parseInt(process.env.PORT ?? '7600', 10)
|
||||
const wsPort = parseInt(process.env.WS_PORT ?? '7601', 10)
|
||||
const port = Number.parseInt(process.env.PORT ?? '7600', 10)
|
||||
const wsPort = Number.parseInt(process.env.WS_PORT ?? '7601', 10)
|
||||
const host = process.env.HOST ?? '127.0.0.1'
|
||||
|
||||
const { app, httpPort } = startServer({
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|||
import { MCP_VERSION, registerTools } from './server.js'
|
||||
import { createStdioRpcBridge } from './stdio-bridge.js'
|
||||
|
||||
const wsPort = parseInt(process.env.WS_PORT ?? '7601', 10)
|
||||
const wsPort = Number.parseInt(process.env.WS_PORT ?? '7601', 10)
|
||||
const wsHost = process.env.HOST ?? '127.0.0.1'
|
||||
const enableEval = process.env.OPENPENCIL_MCP_EVAL === '1'
|
||||
const mcpRoot = process.env.OPENPENCIL_MCP_ROOT?.trim() || process.cwd()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { resolve } from 'path'
|
||||
import { copyFileSync, existsSync, mkdirSync } from 'fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { copyFileSync, existsSync, mkdirSync } from 'node:fs'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ export function useCanvasKitLoader({
|
|||
setCanvasKit(await getCanvasKit())
|
||||
if (isDestroyed()) return
|
||||
|
||||
await new Promise((resolve) => requestAnimationFrame(resolve))
|
||||
await new Promise((resolve) => {
|
||||
requestAnimationFrame(resolve)
|
||||
})
|
||||
createSurface(canvas)
|
||||
await loadFonts()
|
||||
if (isDestroyed()) return
|
||||
|
|
|
|||
|
|
@ -153,8 +153,8 @@ export function createVariableValueActions(
|
|||
function parseVariableValue(variable: Variable, raw: string): VariableValue | undefined {
|
||||
if (variable.type === 'COLOR') return parseColor(raw.startsWith('#') ? raw : `#${raw}`)
|
||||
if (variable.type === 'FLOAT') {
|
||||
const num = parseFloat(raw)
|
||||
return isNaN(num) ? undefined : num
|
||||
const num = Number.parseFloat(raw)
|
||||
return Number.isNaN(num) ? undefined : num
|
||||
}
|
||||
if (variable.type === 'BOOLEAN') return raw.toLowerCase() === 'true'
|
||||
return raw
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ async function diff() {
|
|||
.quiet()
|
||||
.nothrow()
|
||||
|
||||
const diffPixels = parseInt(result.stderr.toString().trim(), 10) || 0
|
||||
const diffPixels = Number.parseInt(result.stderr.toString().trim(), 10) || 0
|
||||
const [w, h] = figmaSize.split('x').map(Number)
|
||||
const total = w * h
|
||||
const pct = ((diffPixels / total) * 100).toFixed(2)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
export function yieldToUI(): Promise<void> {
|
||||
return new Promise((resolve) => requestAnimationFrame(() => resolve()))
|
||||
return new Promise((resolve) => {
|
||||
requestAnimationFrame(() => resolve())
|
||||
})
|
||||
}
|
||||
|
||||
type ViewportSize = { width: number; height: number }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ async function readClipboardHtml() {
|
|||
const items = await navigator.clipboard.read()
|
||||
for (const item of items) {
|
||||
if (!item.types.includes('text/html')) continue
|
||||
return await (await item.getType('text/html')).text()
|
||||
return (await item.getType('text/html')).text()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,9 @@ export function closeTab(tabId: string) {
|
|||
}
|
||||
|
||||
function yieldToUI(): Promise<void> {
|
||||
return new Promise((resolve) => requestAnimationFrame(() => resolve()))
|
||||
return new Promise((resolve) => {
|
||||
requestAnimationFrame(() => resolve())
|
||||
})
|
||||
}
|
||||
|
||||
export async function openFileInNewTab(
|
||||
|
|
|
|||
|
|
@ -86,7 +86,9 @@ test('CJK text waits for fallback fonts and repaints after they load', async ({
|
|||
const beforeFallbackRenderCount = fallbackRenderCount
|
||||
|
||||
releaseCJKFallback?.()
|
||||
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, 0)
|
||||
})
|
||||
await new Promise(requestAnimationFrame)
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,9 @@ describe('acp-permission', () => {
|
|||
const result = await promise
|
||||
expect(result.outcome.optionId).toBe('allow')
|
||||
// Timer should be cleared — wait to ensure no stale timeout fires
|
||||
await new Promise((r) => setTimeout(r, 50))
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, 50)
|
||||
})
|
||||
expect(permissionQueue.value).toHaveLength(0)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { expect, setDefaultTimeout, test } from 'bun:test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
|
||||
import { cliSourcePath, repoPath } from '#tests/helpers/paths'
|
||||
import { heavy } from '#tests/helpers/test-utils'
|
||||
|
|
@ -54,7 +54,7 @@ heavy('eval CLI', () => {
|
|||
'return figma.root.children.length'
|
||||
])
|
||||
expect(exitCode).toBe(0)
|
||||
const count = parseInt(stdout, 10)
|
||||
const count = Number.parseInt(stdout, 10)
|
||||
expect(count).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -2,26 +2,24 @@ import { describe, test, expect } from 'bun:test'
|
|||
|
||||
import { createUndoManager, noop, undoEntry } from '#tests/helpers/undo'
|
||||
|
||||
function assignValue(setValue: (value: number) => void, value: number) {
|
||||
return () => setValue(value)
|
||||
}
|
||||
|
||||
describe('UndoManager idle-timer batching', () => {
|
||||
test('rapid pushes inside a batch produce a single undo entry', () => {
|
||||
const undo = createUndoManager()
|
||||
let value = 0
|
||||
|
||||
const setValue = (nextValue: number) => {
|
||||
value = nextValue
|
||||
}
|
||||
|
||||
undo.beginBatch('drag color')
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
const prev = value
|
||||
const next = i
|
||||
undo.push(
|
||||
undoEntry(
|
||||
`step ${i}`,
|
||||
() => {
|
||||
value = next
|
||||
},
|
||||
() => {
|
||||
value = prev
|
||||
}
|
||||
)
|
||||
)
|
||||
undo.push(undoEntry(`step ${i}`, assignValue(setValue, next), assignValue(setValue, prev)))
|
||||
value = next
|
||||
}
|
||||
undo.commitBatch()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, test, expect, beforeAll, setDefaultTimeout } from 'bun:test'
|
||||
import { readFileSync } from 'fs'
|
||||
import { resolve } from 'path'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
import {
|
||||
parseFigFile,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, setDefaultTimeout, test } from 'bun:test'
|
||||
import { readFileSync } from 'fs'
|
||||
import { readFileSync } from 'node:fs'
|
||||
|
||||
import { importNodeChanges } from '#core/kiwi'
|
||||
import { parseFigBuffer } from '#core/kiwi/fig/parse/core'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { readFileSync } from 'fs'
|
||||
import { resolve } from 'path'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
import { bench, group, run } from 'mitata'
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ describe('FrameStats', () => {
|
|||
expect(stats.scenePictureCacheHit).toBe(true)
|
||||
})
|
||||
|
||||
it('handles GPU time as NaN initially', () => {
|
||||
it('handles GPU time as Number.NaN initially', () => {
|
||||
const stats = new FrameStats()
|
||||
stats.recordFrame(1)
|
||||
expect(stats.gpuTime).toBe(0)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { beforeAll, describe, expect, test } from 'bun:test'
|
||||
import { readFileSync } from 'fs'
|
||||
import { readFileSync } from 'node:fs'
|
||||
|
||||
import {
|
||||
computeAllLayouts,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { readFileSync } from 'fs'
|
||||
import { resolve } from 'path'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
import { parseFigFile } from '@open-pencil/core'
|
||||
import type { SceneGraph, SceneNode } from '@open-pencil/core'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { resolve } from 'path'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
export function createOpenPencilAliases(rootDir: string) {
|
||||
const emptyNodeModule = resolve(rootDir, 'vite/empty-node-module.ts')
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { randomUUID } from 'crypto'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { automationPlugin } from '../src/app/automation/bridge/vite-plugin'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { copyFileSync, createReadStream, existsSync, mkdirSync } from 'fs'
|
||||
import { copyFileSync, createReadStream, existsSync, mkdirSync } from 'node:fs'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
|
||||
import type { Connect, Plugin, ResolvedConfig } from 'vite'
|
||||
|
|
|
|||
Loading…
Reference in a new issue