-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathindex.ts
118 lines (103 loc) · 3.39 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { promises as fs } from 'node:fs'
import * as path from 'node:path'
import camelcase from 'camelcase'
import type { Transformer } from 'postcss'
import * as postcssModules from 'postcss-modules'
import reserved from 'reserved-words'
import type { Plugin } from 'rollup'
import postcss, { type PostCSSPluginConf } from 'rollup-plugin-postcss'
function fixname(name: string) {
const ccName = camelcase(name)
return reserved.check(ccName) ? `$${ccName}$` : ccName
}
const formatCSSDefinition = (name: string, classNames: string[]) => `\
${classNames
.filter((n) => !/-/.test(n))
.map((t) => `export const ${t}: string`)
.join('\n')}
interface Namespace {
${classNames.map((t) => `${JSON.stringify(t)}: string,`).join('\n\t')}
}
declare const ${name}: Namespace
export default ${name}`
async function writeCSSDefinition(
cssPath: string,
classNames: string[],
): Promise<string> {
const name = fixname(path.basename(cssPath, '.css'))
const definition = formatCSSDefinition(name, classNames)
const dPath = `${cssPath}.d.ts`
await fs.writeFile(dPath, `${definition}\n`)
return dPath
}
export type DefinitionCB = (dPath: string) => void | PromiseLike<void>
type PostcssOptions = Parameters<postcssModules>[0]
type PostcssModulesTokens = Parameters<
NonNullable<PostcssOptions['getJSON']>
>[1]
class CSSExports {
writeDefinitions: boolean | DefinitionCB
// exports: { [moduleName: string]: PostcssModulesTokens }
constructor(writeDefinitions: boolean | DefinitionCB) {
this.writeDefinitions = writeDefinitions
}
definitionCB = async (dPath: string) => {
if (typeof this.writeDefinitions === 'function') {
await Promise.resolve(this.writeDefinitions(dPath))
} else {
console.log(`${dPath} written`)
}
}
getJSON = async (id: string, exportTokens: PostcssModulesTokens) => {
const ccTokens: PostcssModulesTokens = {}
for (const className of Object.keys(exportTokens)) {
ccTokens[fixname(className)] = exportTokens[className]
ccTokens[className] = exportTokens[className]
}
if (this.writeDefinitions) {
const dPath = await writeCSSDefinition(id, Object.keys(ccTokens))
await this.definitionCB(dPath)
}
}
}
export interface Options extends PostCSSPluginConf {
/** Write typescript definitions next to source files? Default: false */
writeDefinitions?: boolean | DefinitionCB
}
type PluginFunc = (options: PostCSSPluginConf) => Plugin
export default function rollupPluginPostCSSModules(
options: Options = {},
): Plugin {
const {
plugins = [],
// own options
writeDefinitions = false,
modules = {},
namedExports = fixname,
...rest
} = options
if ('getExport' in rest) {
throw new Error("'getExport' is no longer supported.")
}
if (
plugins.some((p) => (p as Transformer).postcssPlugin === 'postcss-modules')
) {
throw new Error(
"'rollup-plugin-postcss-modules' provides a 'postcss-modules' plugin, you cannot specify your own. Use the `modules` config key for configuration.",
)
}
const modulesOptions = modules === true ? {} : modules
if (modulesOptions === false || modulesOptions.getJSON) {
throw new Error(
"'rollup-plugin-postcss-modules' provides a 'postcss-modules' plugin and its `getJSON()`. You cannot specify `modules.getJSON`",
)
}
const { getJSON } = new CSSExports(writeDefinitions)
return (postcss as unknown as PluginFunc)({
plugins: [...plugins],
modules: { getJSON, ...modulesOptions },
autoModules: false,
namedExports,
...rest,
})
}