@herb-tools/tailwind-class-sorter 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,11 +30,11 @@ export interface TailwindContext {
30
30
  };
31
31
  }
32
32
  export interface SortEnv {
33
- context: TailwindContext;
34
- generateRules: (classes: Iterable<string>, context: TailwindContext) => [bigint][];
33
+ context: TailwindContext | null;
34
+ generateRules: ((classes: Iterable<string>, context: TailwindContext) => [bigint][]) | null;
35
35
  options: SortTailwindClassesOptions;
36
36
  }
37
37
  export interface ContextContainer {
38
- context: any;
39
- generateRules: (classes: Iterable<string>, context: TailwindContext) => [bigint][];
38
+ context: any | null;
39
+ generateRules: ((classes: Iterable<string>, context: TailwindContext) => [bigint][]) | null;
40
40
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "name": "@herb-tools/tailwind-class-sorter",
4
4
  "description": "Standalone Tailwind CSS class sorter with Prettier plugin compatibility, extracted from tailwindlabs/prettier-plugin-tailwindcss",
5
- "version": "0.8.1",
5
+ "version": "0.8.2",
6
6
  "license": "MIT",
7
7
  "main": "./dist/tailwind-class-sorter.cjs",
8
8
  "module": "./dist/tailwind-class-sorter.esm.js",
@@ -32,6 +32,8 @@
32
32
  "build": "yarn clean && rollup -c",
33
33
  "dev": "rollup -c -w",
34
34
  "clean": "rimraf dist",
35
+ "setup-fixtures": "bash scripts/setup-fixtures.sh",
36
+ "pretest": "yarn setup-fixtures",
35
37
  "test": "vitest run",
36
38
  "test:watch": "vitest --watch",
37
39
  "prepublishOnly": "yarn clean && yarn build && yarn test"
package/src/config.ts CHANGED
@@ -8,12 +8,6 @@ import { createJiti, type Jiti } from 'jiti'
8
8
  import postcss from 'postcss'
9
9
  // @ts-ignore
10
10
  import postcssImport from 'postcss-import'
11
- // @ts-ignore
12
- import { generateRules as generateRulesFallback } from 'tailwindcss/lib/lib/generateRules'
13
- // @ts-ignore
14
- import { createContext as createContextFallback } from 'tailwindcss/lib/lib/setupContextUtils'
15
- import loadConfigFallback from 'tailwindcss/loadConfig'
16
- import resolveConfigFallback from 'tailwindcss/resolveConfig'
17
11
  import type { RequiredConfig } from 'tailwindcss/types/config.js'
18
12
  import { expiringMap } from './expiring-map.js'
19
13
  import { resolveCssFrom, resolveJsFrom } from './resolve'
@@ -84,22 +78,53 @@ async function loadTailwindConfig(
84
78
  tailwindConfigPath: string | null,
85
79
  entryPoint: string | null,
86
80
  ): Promise<ContextContainer> {
87
- let createContext = createContextFallback
88
- let generateRules = generateRulesFallback
89
- let resolveConfig = resolveConfigFallback
90
- let loadConfig = loadConfigFallback
81
+ let createContext: any
82
+ let generateRules: any
83
+ let resolveConfig: any
84
+ let loadConfig: any
91
85
  let tailwindConfig: RequiredConfig = { content: [] }
92
86
 
93
87
  try {
94
- let pkgFile = resolveJsFrom(baseDir, `${pkgName}/package.json`)
95
- let pkgDir = path.dirname(pkgFile)
88
+ let pkgPath = resolveJsFrom(baseDir, pkgName)
89
+ let pkgJsonPath: string
90
+
91
+ try {
92
+ const Module = require('module')
93
+ const requireFromBase = Module.createRequire(path.join(baseDir, 'index.js'))
94
+
95
+ pkgJsonPath = requireFromBase.resolve(`${pkgName}/package.json`)
96
+ } catch {
97
+ // Fallback: assume pkgPath is in a subdirectory of the package
98
+ // Let's walk up until we find package.json
99
+ let currentDir = path.dirname(pkgPath)
100
+
101
+ while (currentDir !== path.dirname(currentDir)) {
102
+ const candidatePkgJson = path.join(currentDir, 'package.json')
103
+
104
+ try {
105
+ require('fs').accessSync(candidatePkgJson)
106
+ pkgJsonPath = candidatePkgJson
107
+ break
108
+ } catch {}
109
+
110
+ currentDir = path.dirname(currentDir)
111
+ }
112
+
113
+ if (!pkgJsonPath!) {
114
+ throw new Error('Could not find Tailwind CSS package.json')
115
+ }
116
+ }
117
+
118
+ let pkgDir = path.dirname(pkgJsonPath)
96
119
 
97
120
  try {
98
121
  let v4 = await loadV4(baseDir, pkgDir, pkgName, entryPoint)
99
122
  if (v4) {
100
123
  return v4
101
124
  }
102
- } catch {}
125
+ } catch (err) {
126
+ // V4 loading failed, will try v3 below
127
+ }
103
128
 
104
129
  resolveConfig = require(path.join(pkgDir, 'resolveConfig'))
105
130
  createContext = require(
@@ -111,7 +136,9 @@ async function loadTailwindConfig(
111
136
 
112
137
  // Prior to `tailwindcss@3.3.0` this won't exist so we load it last
113
138
  loadConfig = require(path.join(pkgDir, 'loadConfig'))
114
- } catch {}
139
+ } catch (err: any) {
140
+ // Tailwind isn't installed or loading failed, will use defaults
141
+ }
115
142
 
116
143
  if (tailwindConfigPath) {
117
144
  try {
@@ -123,10 +150,15 @@ async function loadTailwindConfig(
123
150
  }
124
151
  }
125
152
 
126
- // suppress "empty content" warning
153
+ if (!resolveConfig || !createContext || !generateRules) {
154
+ return {
155
+ context: null,
156
+ generateRules: null,
157
+ }
158
+ }
159
+
127
160
  tailwindConfig.content = ['no-op']
128
161
 
129
- // Create the context
130
162
  let context = createContext(resolveConfig(tailwindConfig))
131
163
 
132
164
  return {
@@ -340,5 +372,29 @@ function getEntryPoint(options: SortTailwindClassesOptions, baseDir: string): st
340
372
  return path.resolve(baseDir, options.tailwindConfig)
341
373
  }
342
374
 
375
+ try {
376
+ const commonPaths = [
377
+ 'app/assets/tailwind/application.css',
378
+ 'app/assets/stylesheets/application.tailwind.css',
379
+ 'app/assets/stylesheets/application.css',
380
+ 'src/styles/tailwind.css',
381
+ 'src/tailwind.css',
382
+ 'styles/tailwind.css',
383
+ 'tailwind.css',
384
+ 'app.css',
385
+ 'src/app.css',
386
+ ]
387
+
388
+ for (const cssPath of commonPaths) {
389
+ const fullPath = path.resolve(baseDir, cssPath)
390
+ try {
391
+ require('fs').accessSync(fullPath, require('fs').constants.R_OK)
392
+ return fullPath
393
+ } catch {
394
+ // File doesn't exist or isn't readable, continue to next path
395
+ }
396
+ }
397
+ } catch {}
398
+
343
399
  return null
344
400
  }
package/src/sorting.ts CHANGED
@@ -17,6 +17,10 @@ function getClassOrderPolyfill(
17
17
  classes: string[],
18
18
  { env }: { env: SortEnv },
19
19
  ): [string, bigint | null][] {
20
+ if (!env.context || !env.generateRules) {
21
+ return classes.map(name => [name, null] as [string, bigint | null])
22
+ }
23
+
20
24
  // A list of utilities that are used by certain Tailwind CSS utilities but
21
25
  // that don't exist on their own. This will result in them "not existing" and
22
26
  // sorting could be weird since you still require them in order to make the
@@ -48,6 +52,10 @@ function getClassOrderPolyfill(
48
52
  }
49
53
 
50
54
  function reorderClasses(classList: string[], { env }: { env: SortEnv }) {
55
+ if (!env.context) {
56
+ return classList.map(name => [name, null] as [string, bigint | null])
57
+ }
58
+
51
59
  let orderedClasses = env.context.getClassOrder
52
60
  ? env.context.getClassOrder(classList)
53
61
  : getClassOrderPolyfill(classList, { env })
package/src/types.ts CHANGED
@@ -38,18 +38,18 @@ export interface TailwindContext {
38
38
  }
39
39
 
40
40
  export interface SortEnv {
41
- context: TailwindContext
42
- generateRules: (
41
+ context: TailwindContext | null
42
+ generateRules: ((
43
43
  classes: Iterable<string>,
44
44
  context: TailwindContext,
45
- ) => [bigint][]
45
+ ) => [bigint][]) | null
46
46
  options: SortTailwindClassesOptions
47
47
  }
48
48
 
49
49
  export interface ContextContainer {
50
- context: any
51
- generateRules: (
50
+ context: any | null
51
+ generateRules: ((
52
52
  classes: Iterable<string>,
53
53
  context: TailwindContext,
54
- ) => [bigint][]
54
+ ) => [bigint][]) | null
55
55
  }