Passed
Push — master ( fdd119...91528d )
by Andrii
02:18
created

index.ts ➔ makeOpts   A

Complexity

Conditions 2

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
dl 0
loc 19
rs 9.75
c 0
b 0
f 0
1
import {resolve} from "path"
2
import { regexpize, extractDefaults, readlineSync } from './utils'
3
import schema = require("./schema.json")
4
import type { Options } from './options.types'
5
import replaceMultiplicated = require('./replaceMultiplicated')
6
import collector = require('./collector')
7
import rewrite = require('./rewrite')
8
import type { InternalOptions, WithSource } from './$defs.types'
9
import meta = require("./meta.json")
10
11
type Opts = Required<Options>
12
13
const {keys: $keys} = Object
14
, defaultOptions = extractDefaults(schema) as Opts
15
, {
16
  name,
17
  signature,
18
  templateEol,
19
  templatePath
20
} = meta
21
, defaultTemplate = readlineSync(resolve(__dirname, templatePath), templateEol)
22
23
const creator8 = (opts?: Options) => {
24
  const options = makeOpts(opts)
25
26
  return {
27
    postcssPlugin: name,
28
    prepare: (result: {
29
      warn: (arg: string) => any
30
      root: WithSource
31
    }) => {
32
      //TODO #12 template update check
33
34
      /* istanbul ignore next `source === undefined` for manually created node with `.decl` */
35
      if (!result.root?.source?.input.file)
36
        return {}
37
38
      try {
39
        OptsCheck(options)
40
      } catch ({message}) {
41
        // TODO throw error
42
        result.warn(message)
43
        return {}
44
      }
45
46
      // https://jsbench.me/q5km8xdgbb
47
      const identifiers: Record<string, true> = {}
48
49
      return {
50
        RuleExit: collector(identifiers, options),
51
        RootExit: writer(identifiers, options)
52
      }
53
    }
54
  } //as Plugin
55
}
56
57
creator8.postcss = true
58
59
export = creator8
60
61
function OptsCheck({
62
  destination,
63
  identifierParser
64
}: {destination: any} & Pick<InternalOptions, "identifierParser">) {
65
  if (!(destination === false || destination !== null && typeof destination === "object"))
66
    throw Error("Destination is of wrong type")
67
68
  //TODO check sticky
69
  if (!identifierParser.flags.includes('g'))
70
    throw Error('identifierParser should have global flag')
71
}
72
73
function makeOpts(opts?: Options) {
74
  const options = !opts ? defaultOptions : {...defaultOptions, ...opts}
75
  , {
76
    eol,
77
    destination,
78
    //TODO several keywords?
79
    identifierKeyword,
80
    identifierMatchIndex,
81
    identifierCleanupReplace,
82
  } = options
83
84
  return {
85
    eol,
86
    destination,
87
    identifierKeyword,
88
    identifierMatchIndex,
89
    identifierCleanupReplace,
90
    ...internalOpts(options)
91
  }
92
}
93
94
function internalOpts({
95
  eol,
96
  template: templatePath,
97
  identifierPattern: cssP,
98
  identifierCleanupPattern: escapedP,
99
  allowedAtRules: atRules
100
}: Pick<Opts, "eol"|"template"|"identifierPattern"|"identifierCleanupPattern"|"allowedAtRules">): InternalOptions {
101
  const identifierParser = regexpize(cssP, "g")
102
  , identifierCleanupParser = regexpize(escapedP, "g")
103
  //TODO check `templatePath === ""`
104
  , templateContent = typeof templatePath === "string"
105
  // TODO not sync
106
  ? readlineSync(templatePath, eol)
107
  : defaultTemplate
108
109
  , allowedAtRuleNames = new Set(atRules)
110
111
  return {
112
    identifierParser,
113
    identifierCleanupParser,
114
    templateContent,
115
    allowedAtRuleNames
116
  }
117
}
118
119
function writer(
120
  identifiers: Record<string, any>,
121
  {
122
    eol,
123
    templateContent,
124
    identifierKeyword,
125
    destination
126
  }: Pick<Opts, "eol"|"identifierKeyword"|"destination">
127
  & Pick<InternalOptions, "templateContent">
128
) {
129
  return (async ({source}: WithSource) => {
130
    const file = source!.input.file!
131
    , lines = replaceMultiplicated(
132
      signature.concat(templateContent),
133
      identifierKeyword,
134
      $keys(identifiers)
135
      //TODO Change with option
136
      .sort()
137
    )
138
139
    if (destination === false)
140
      await rewrite(`${file}.d.ts`, lines, eol)
141
    else
142
      destination[file] = lines
143
  })
144
}
145