pogi 2.11.0

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.
Files changed (82) hide show
  1. package/.vscode/launch.json +35 -0
  2. package/CHANGELOG.md +277 -0
  3. package/LICENSE +21 -0
  4. package/README.md +85 -0
  5. package/docs/API/PgDb.md +218 -0
  6. package/docs/API/PgSchema.md +91 -0
  7. package/docs/API/PgTable.md +365 -0
  8. package/docs/API/QueryOptions.md +77 -0
  9. package/docs/API/condition.md +133 -0
  10. package/docs/connection.md +91 -0
  11. package/docs/css/docs.css +164 -0
  12. package/docs/executingSqlFile.md +44 -0
  13. package/docs/faq.md +15 -0
  14. package/docs/functions.md +19 -0
  15. package/docs/generatingInterfaceForTables.md +35 -0
  16. package/docs/index.md +48 -0
  17. package/docs/logger.md +40 -0
  18. package/docs/mappingDatabaseTypes.md +89 -0
  19. package/docs/notification.md +19 -0
  20. package/docs/pitfalls.md +73 -0
  21. package/docs/streams.md +68 -0
  22. package/docs/transaction.md +65 -0
  23. package/lib/bin/generateInterface.d.ts +1 -0
  24. package/lib/bin/generateInterface.js +53 -0
  25. package/lib/bin/generateInterface.js.map +1 -0
  26. package/lib/connectionOptions.d.ts +25 -0
  27. package/lib/connectionOptions.js +3 -0
  28. package/lib/connectionOptions.js.map +1 -0
  29. package/lib/index.d.ts +6 -0
  30. package/lib/index.js +10 -0
  31. package/lib/index.js.map +1 -0
  32. package/lib/pgConverters.d.ts +10 -0
  33. package/lib/pgConverters.js +66 -0
  34. package/lib/pgConverters.js.map +1 -0
  35. package/lib/pgDb.d.ts +86 -0
  36. package/lib/pgDb.js +745 -0
  37. package/lib/pgDb.js.map +1 -0
  38. package/lib/pgDbLogger.d.ts +5 -0
  39. package/lib/pgDbLogger.js +3 -0
  40. package/lib/pgDbLogger.js.map +1 -0
  41. package/lib/pgDbOperators.d.ts +113 -0
  42. package/lib/pgDbOperators.js +44 -0
  43. package/lib/pgDbOperators.js.map +1 -0
  44. package/lib/pgSchema.d.ts +16 -0
  45. package/lib/pgSchema.js +16 -0
  46. package/lib/pgSchema.js.map +1 -0
  47. package/lib/pgTable.d.ts +131 -0
  48. package/lib/pgTable.js +322 -0
  49. package/lib/pgTable.js.map +1 -0
  50. package/lib/pgUtils.d.ts +31 -0
  51. package/lib/pgUtils.js +157 -0
  52. package/lib/pgUtils.js.map +1 -0
  53. package/lib/queryAble.d.ts +76 -0
  54. package/lib/queryAble.js +330 -0
  55. package/lib/queryAble.js.map +1 -0
  56. package/lib/queryWhere.d.ts +8 -0
  57. package/lib/queryWhere.js +249 -0
  58. package/lib/queryWhere.js.map +1 -0
  59. package/mkdocs.yml +25 -0
  60. package/package.json +65 -0
  61. package/spec/resources/init.sql +122 -0
  62. package/spec/resources/throw_exception.sql +5 -0
  63. package/spec/resources/tricky.sql +13 -0
  64. package/spec/run.js +5 -0
  65. package/spec/support/jasmine.json +9 -0
  66. package/src/bin/generateInterface.ts +54 -0
  67. package/src/connectionOptions.ts +42 -0
  68. package/src/index.ts +6 -0
  69. package/src/pgConverters.ts +55 -0
  70. package/src/pgDb.ts +820 -0
  71. package/src/pgDbLogger.ts +13 -0
  72. package/src/pgDbOperators.ts +62 -0
  73. package/src/pgSchema.ts +15 -0
  74. package/src/pgTable.ts +401 -0
  75. package/src/pgUtils.ts +176 -0
  76. package/src/queryAble.ts +393 -0
  77. package/src/queryWhere.ts +326 -0
  78. package/src/test/pgDbOperatorSpec.ts +492 -0
  79. package/src/test/pgDbSpec.ts +1339 -0
  80. package/src/test/pgServiceRestartTest.ts +1500 -0
  81. package/src/tsconfig.json +33 -0
  82. package/utils_sql/lower.sql +4 -0
@@ -0,0 +1,77 @@
1
+ ##SqlQueryOption, InsertOption
2
+ You can set the logger.
3
+ ```js
4
+ export interface SqlQueryOptions {
5
+ logger?: PgDbLogger;
6
+ }
7
+ ```
8
+
9
+ ##QueryOptions
10
+ Query (`select`) option has to follow the following interface:
11
+
12
+ ```js
13
+ interface QueryOptions {
14
+ limit?:number;
15
+ offset?: number;
16
+ orderBy?: string|string[]|{[fieldName:string]:'asc'|'desc'};//free text or column list
17
+ groupBy?:string|string[]; //free text or column list
18
+ fields?: string|string[]; //free text or column list
19
+ skipUndefined?:boolean; //if there is an undefined value in the conditions, shall it be skipped. Default raise error.
20
+ logger?:PgDbLogger;
21
+ distinct?: boolean; // SELECT DISTINCT statement
22
+ forUpdate?: boolean; // FOR UPDATE statement
23
+ }
24
+ ```
25
+ where orderBy/groupBy/fields can be either an array (in that case will get quotation if needed)
26
+ or a free text string with all the possibilities.
27
+
28
+ logger can be specified for the current query only.
29
+
30
+ ```js
31
+ await pgdb.users.find({medal:['g','s','b']}, {orderBy:'sum(*)', groupBy:['country'], fields:'sum(*) as numberOfMedals, country'});
32
+ ```
33
+ ### orderBy
34
+ You can do as you like:
35
+ ```js
36
+ await pgdb.users.find({}, {orderBy:{name:'desc', ageCategory:'asc'}});
37
+ await pgdb.users.find({}, {orderBy:['name desc', 'ageCategory asc']});
38
+ await pgdb.users.find({}, {orderBy:['-name', '+ageCategory']});
39
+ await pgdb.users.find({}, {orderBy:['name', 'ageCategory']});
40
+ await pgdb.users.find({}, {orderBy:'name dec, "ageCategory" asc'});
41
+ ```
42
+ ### groupBy
43
+ ```js
44
+ await pgdb.users.find({}, {groupBy:'name, "ageCategory", count(*)'});
45
+ await pgdb.users.find({}, {groupBy:['name', 'ageCategory', 'count(*)']});
46
+ ```
47
+
48
+ ### skipUndefined
49
+ ```js
50
+ await pgdb.users.find({}, {name:'joe', password:undefined}); //raise error
51
+ await pgdb.users.find({}, {name:'joe', password:undefined}, {skipUndefined:true}); //return the record with name 'joe'
52
+ ```
53
+
54
+ ##UpdateDeleteOption
55
+ ```js
56
+ export interface SqlQueryOptions {
57
+ skipUndefined?:boolean; //if there is an undefined value in the conditions, shall it be skipped. Default raise error.
58
+ logger?: PgDbLogger;
59
+ }
60
+ ```
61
+
62
+ ## & Return, & Stream
63
+ Additional interfaces to set return value type.
64
+
65
+ With `stream:true` query will return with stream instead of the populated result.
66
+
67
+ With `return *` insert / update / delete query will return the affected rows (this is the default).
68
+
69
+ `return string[]` is the same as '*' but only return with the specified columns
70
+ ```js
71
+ export interface Return {
72
+ return?:string[]|'*';
73
+ }
74
+ export interface Stream {
75
+ stream: true;
76
+ }
77
+ ```
@@ -0,0 +1,133 @@
1
+ #Conditions and operators
2
+
3
+ ##Basic examples
4
+
5
+ | Condition | SQL
6
+ | ------------- |:--------------
7
+ | {id: 2} | "id" = 2
8
+ | {'id <': 2} | "id" < 2
9
+ | {'id >': 2} | "id" > 2
10
+ | {'id <=': 2} | "id" <= 2
11
+ | {'id >=': 2} | "id" >= 2
12
+ | {'id !=': 2} | "id" != 2
13
+ | {'id <>': 2} | "id" != 2
14
+ | {'id': null} | "id" is null
15
+ | {'id !=': null} | "id" is not null
16
+ | {'id is not': null}| "id" is not null
17
+ | {'id in':[1,2,3]} | "id" in (1,2,3)
18
+ | {'id not in':[1,2,3]}| "id" not in (1,2,3)
19
+
20
+ ###Extended
21
+
22
+ | Condition | SQL
23
+ | ------------- |:--------------
24
+ | {id: [1,2,3]} | "id" in (1,2,3)
25
+ | {'id <>': [1,2,3]} | "id" not in (1,2,3)
26
+ | {'id =*':'gamma'} | LOWER("id") = LOWER('gamma')
27
+ | {'fruits =*':'KiWi'} | LOWER("fruits") && '{kiwi}' //Has to have the LOWER function defined see below. (It uses GIN index if defined on fruits)
28
+
29
+ ##Pattern matching
30
+ [PostgreSQL Documentation](https://www.postgresql.org/docs/9.6/static/functions-matching.html)
31
+
32
+ | Condition | SQL
33
+ | ------------- |:--------------
34
+ | {'id ~~': 'a%'} | "id" LIKE 'a%'
35
+ | {'id !~~': 'a%'} | "id" NOT LIKE 'a%'
36
+ | {'id like': 'a%'} | "id" LIKE 'a%'
37
+ | {'id not like': 'a%'} | "id" NOT LIKE 'a%'
38
+ | {'id ~~*': 'a%'} | "id" ILIKE 'a%'
39
+ | {'id !~~*': 'a%'} | "id" NOT ILIKE 'a%'
40
+ | {'id ilike': 'a%'} | "id" ILIKE 'a%'
41
+ | {'id not ilike': 'a%'} | "id" NOT ILIKE 'a%'
42
+ | {'id similar to': 'a%'} | "id" SIMILAR TO 'a%'
43
+ | {'id not similar to': 'a%'} | "id" NOT SIMILAR TO 'a%'
44
+ | {'id ~': '^a'} | "id" ~ '^a'
45
+ | {'id !~': '^a'} | "id" !~ '^a'
46
+ | {'id ~*': '^a'} | "id" ~* '^a'
47
+ | {'id !~*': '^a'} | "id" !~* '^a'
48
+ | {'id is distinct from': '^a'}| "id" IS DISTINCT FROM '^a'
49
+ | {'id is not distinct from': '^a'}| "id" IS NOT DISTINCT FROM '^a'
50
+
51
+ ###Extended
52
+
53
+ | Condition | SQL
54
+ | ------------- |:--------------
55
+ | {'id ~~': ['1%','2%','3%']} | "id" LIKE ANY('{1%,2%,3%}')
56
+ | {'id !~~': ['1%','2%','3%']}| "id" NOT LIKE ALL('{1%,2%,3%}')
57
+ | {'id ~': ['^1','^2','^3']} | "id" LIKE ANY('{^1,^2,^3}')
58
+ | {'id !~': ['^1','^2','^3']} | "id" NOT LIKE ALL('{^1,^2,^3}')
59
+
60
+
61
+ ##Array type
62
+ [PostgreSQL Documentation](https://www.postgresql.org/docs/current/static/functions-array.html)
63
+
64
+ | Condition | SQL | note
65
+ | ------------- |:-------------- | :--------------
66
+ | {'ids @>':[1,2,3]} | "ids" @> '{1,2,3}' | ids contains all of 1,2,3
67
+ | {'ids <@':[1,2,3]} | "ids" <@ '{1,2,3}' | ids is a subset of {1,2,3}
68
+ | {'ids &&':[1,2,3]} | "ids" && '{1,2,3}' | ids overlaps with {1,2,3}
69
+ | {'ids': [1,2,3]} | "ids" = '{1,2,3}' |
70
+ | {'ids': 'a'} | 'a' = ANY("ids") |
71
+ | {'ids <>': 'a'} | 'a' <> ANY("ids") |
72
+
73
+ Please note that as-of-9.5 `'a' = ANY("ids")` is not using the index in psql. So if have a `GIN` index is defined on the column "ids",
74
+ You should use `{'ids &&': ['a']}` (that is translated to `"ids" && '{a}'`).
75
+
76
+ ###Extended
77
+ | Condition | SQL
78
+ | ------------- |:--------------
79
+ | {'ids ~': 'a%'} | EXISTS (SELECT * FROM (SELECT UNNEST("ids") _el) _arr WHERE _arr._el ~ 'a%')'; //same with all pattern matching operator
80
+ | {'names &&*': ['A','B','C']} | LOWER("names") && '{a, b, c}' //case insensitive overlap operator, has to have the LOWER function defined for arrays (see below)
81
+
82
+ ##Jsonb type
83
+ [PostgreSQL Documentation](https://www.postgresql.org/docs/current/static/functions-json.html)
84
+
85
+ | Condition | SQL | NOTE
86
+ | ------------- |:-------------- |:---
87
+ | {'jdata @>':[1,2,3]} | "jdata" @> '[1,2,3]' |
88
+ | {'jdata @>':{a:1}} | "jdata" @> '{a:1}' |
89
+ | {'jdata <@':[1,2,3]} | "jdata" <@ '[1,2,3]' |
90
+ | {'jdata <@':{a:1}} | "jdata" <@ '{a:1}' |
91
+ | {'jdata ?':'a'} | "jdata" ? 'a' |
92
+ | {'jdata ?&#124;':['a','b']}| "jdata" ?&#124; '{a,b}' |
93
+ | {'jdata ?&':['a','b']} | "jdata" ?& '{a,b}' |
94
+ | {'jdata -> a':{a:3}} | "jdata" -> 'a' = '{"a":3}'::jsonb |
95
+ | {'jdata -> 3':{a:3}} | "jdata" -> 3 = '{"a":3}'::jsonb |if the field is a number, the quote wont apply as it could refer index also
96
+ | {"jdata -> '3'":{a:3}} | "jdata" -> '3' = '{"a":3}'::jsonb |... so you have to apply that manually
97
+ | {'jdata ->> a':3} | "jdata" ->>'a' = 3 |
98
+ | {'jdata ->> 3':3} | "jdata" ->> 3 = 3 |if the field is a number, the quote wont apply as it could refer index also
99
+ | {'jdata ->> '3'":'{"a": 3}'} | "jdata"->>3 = '{"a": 3}' |... so you have to apply that manually
100
+ | {"jdata #> '{a,3}'":{a:3}} | "jdata"#>'{a,3}' = '{"a":3}'::jsonb|surronding {} with ' is possible but not obligatory
101
+ | {"jdata #>> {a,3}":'{"a": 3}'} | "jdata"#>>'{a,3}' = '{"a": 3}' |
102
+ | {"jdata #>> {a} >":'a' | "jdata"#>>'{a}' > 'a' |
103
+
104
+ Note:
105
+
106
+ `->`,`#>` returns as a JsonObject
107
+
108
+ `->>`, `#>>` returns as a string.
109
+
110
+ At the moment they are not converted automatically thou, for `->>` you should use JSON.stringify if needed.
111
+ (this is a later todo, you can help us! :), same goes for `->`, it not converted automaticaly if not an object passed in, but a number or string)
112
+
113
+ ## AND - OR
114
+ condition-expressions can be joined together e.g.:
115
+
116
+ | Condition | SQL
117
+ | ------------- |:--------------
118
+ | {id:1, name:'a'} | id=1 AND name='a'
119
+ | {or: [{id:1}, {name:'a'}]} | id=1 OR name='a'
120
+ | {and: [<br/>&nbsp;&nbsp;&nbsp;&nbsp; or: [{id:1}, {'port >':'1024'}], <br/>&nbsp;&nbsp;&nbsp;&nbsp; or: [{host:'localhost', os:'linux'}, {host:'127.0.0.1'}]<br>]} | (.. OR ..) AND ((.. AND ..) OR ..)
121
+
122
+
123
+ # Definition of LOWER function for array type
124
+ CREATE OR REPLACE FUNCTION LOWER(text[]) RETURNS text[] LANGUAGE SQL IMMUTABLE AS
125
+ $$
126
+ SELECT array_agg(LOWER(value)) FROM unnest($1) value;
127
+ $$;
128
+
129
+
130
+
131
+
132
+
133
+
@@ -0,0 +1,91 @@
1
+ ##Connection
2
+
3
+ ### Connection with connectionString
4
+
5
+ ``` js
6
+ let pgdb = await PgDb.connect({connectionString:'postgres://username@hostname/database', logger:console});
7
+ ```
8
+
9
+ where username/hostname/database are all optional. It could be provided through environment variables (EXPORT).
10
+
11
+ ### Connection with Options Object
12
+ ``` js
13
+ let pgdb = await PgDb.connect({
14
+ host: 'localhost',
15
+ user: 'localuser',
16
+ database: 'localdatabase',
17
+ password: 'localpassword',
18
+ port: 5432,
19
+ max: 10,
20
+ logger:console,
21
+ });
22
+ ```
23
+
24
+ With the following options:
25
+ ``` js
26
+ export interface ConnectionOptions {
27
+ //--- node-postgres specific ----------------------
28
+ host?:string;
29
+ user?:string; //can be specified through PGUSER env variable (defaults USER env var)
30
+ database?:string; //can be specified through PGDATABASE env variable (defaults USER env var)
31
+ password?:string; //can be specified through PGPASSWORD env variable
32
+ port?:number; //can be specified through PGPORT env variable
33
+ connectionString?:string; //'postgres://username:password@hostname/database'
34
+
35
+ poolSize?:number; //number of connections to use in connection pool. 0 - disable pooling
36
+ min?:number; //minimum number of resources to keep in pool at any given time.
37
+ max?:number;
38
+ reapIntervalMillis?:number; //frequency to check for idle clients within the client pool
39
+ poolLog?:boolean; //pool log function / boolean
40
+ idleTimeoutMillis?:number; // how long a client is allowed to remain idle before being closed
41
+ poolIdleTimeout?:number;
42
+
43
+ rows?:number; //number of rows to return at a time from a prepared statement's portal. 0 will return all rows at once
44
+ binary?:boolean;
45
+ client_encoding?:string;
46
+ ssl?:boolean| any; // TlsOptions;
47
+ application_name?:string;
48
+ fallback_application_name?:string;
49
+ parseInputDatesAsUTC?:boolean;
50
+
51
+ //--- pogi specific ----------------------------
52
+ logger?:PgDbLogger;
53
+ skipUndefined?: 'all' | 'select' | 'none'; //if there is a undefined value in the query condition, what should pogi do. Default is 'none', meaning raise an error if a value is undefined.
54
+ }
55
+ ```
56
+
57
+ About node-postgres specific, more explanation can be found at
58
+ https://github.com/brianc/node-postgres/blob/f6c40b9331c90d794d5fcbb1d4ae2f28eabd4d42/lib/defaults.js
59
+ and
60
+ https://github.com/coopernurse/node-pool
61
+
62
+ ##skipUndefined
63
+ while most settings are self explanatory, this parameter is important. In the first version of pogi
64
+ we ignored the condition if the value was undefined (null was not ignored) in order for ease the use e.g.:
65
+ ``` ts
66
+ let query = {
67
+ powerfull: params.powerfull,
68
+ wise: params.wise
69
+ }
70
+ await pgdb.users.find(query);
71
+ ```
72
+ would return a result if e.g. the `form.wise` would be undefined. While this is comfortable
73
+ in many situation, it can cause critical issues e.g. for update
74
+ ``` ts
75
+ await pgdb.users.update({id:user.id}, {password});
76
+ ```
77
+ would update all users password, in case of the id is undefined. (Although this can be mitigated
78
+ with the `updateOne` function as well.) Still the best if no undefined value is allowed in the conditions.
79
+ Nevertheless to keep the compatibility, this parameter added, and skipUndefined can be set to `all` if needed.
80
+ `select` would allow undefined values for selects/count only but would be strict for update/deletes.
81
+ `none` is the new default value, meaning undefined value considered as programming error and will throw an exception.
82
+ This setting can be specified on query level as well.
83
+
84
+
85
+ ### Static singleton
86
+ If there is no reference kept to the object there is a static function to get the same object everywhere,
87
+ (so no need to keep recreating and set up every time). At the moment doesnt handle env variables beside password.
88
+
89
+ ``` js
90
+ let pgdb = await PgDb.getInstance({connectionString:'postgres://username@hostname/database', logger:console});
91
+ ```
@@ -0,0 +1,164 @@
1
+ .func{
2
+ color:black;
3
+ }
4
+ .type{
5
+ color:chocolate;
6
+ }
7
+ .def{
8
+ color:purple;
9
+ font-weight: bold;
10
+ }
11
+
12
+
13
+ /**
14
+ * Obsidian style
15
+ * ported by Alexander Marenin (http://github.com/ioncreature)
16
+ */
17
+
18
+ .hljs {
19
+ display: block;
20
+ overflow-x: auto;
21
+ padding: 0.5em;
22
+ background: #282b2e;
23
+ -webkit-text-size-adjust: none;
24
+ }
25
+
26
+ .hljs-keyword,
27
+ .hljs-literal,
28
+ .hljs-change,
29
+ .hljs-winutils,
30
+ .hljs-flow,
31
+ .nginx .hljs-title,
32
+ .css .hljs-id,
33
+ .tex .hljs-special {
34
+ color: #93c763;
35
+ }
36
+
37
+ .hljs-number {
38
+ color: #ffcd22;
39
+ }
40
+
41
+ .hljs {
42
+ color: #e0e2e4;
43
+ }
44
+
45
+ .css .hljs-tag,
46
+ .css .hljs-pseudo {
47
+ color: #d0d2b5;
48
+ }
49
+
50
+ .hljs-attribute,
51
+ .hljs .hljs-constant {
52
+ color: #668bb0;
53
+ }
54
+
55
+ .xml .hljs-attribute {
56
+ color: #b3b689;
57
+ }
58
+
59
+ .xml .hljs-tag .hljs-value {
60
+ color: #e8e2b7;
61
+ }
62
+
63
+ .hljs-code,
64
+ .hljs-class .hljs-title,
65
+ .hljs-header {
66
+ color: white;
67
+ }
68
+
69
+ .hljs-class,
70
+ .hljs-hexcolor {
71
+ color: #93c763;
72
+ }
73
+
74
+ .hljs-regexp {
75
+ color: #d39745;
76
+ }
77
+
78
+ .hljs-at_rule,
79
+ .hljs-at_rule .hljs-keyword {
80
+ color: #a082bd;
81
+ }
82
+
83
+ .hljs-doctype {
84
+ color: #557182;
85
+ }
86
+
87
+ .hljs-link_url,
88
+ .hljs-tag,
89
+ .hljs-tag .hljs-title,
90
+ .hljs-bullet,
91
+ .hljs-subst,
92
+ .hljs-emphasis,
93
+ .hljs-type,
94
+ .hljs-preprocessor,
95
+ .hljs-pragma,
96
+ .ruby .hljs-class .hljs-parent,
97
+ .hljs-built_in,
98
+ .django .hljs-template_tag,
99
+ .django .hljs-variable,
100
+ .smalltalk .hljs-class,
101
+ .django .hljs-filter .hljs-argument,
102
+ .smalltalk .hljs-localvars,
103
+ .smalltalk .hljs-array,
104
+ .hljs-attr_selector,
105
+ .hljs-pseudo,
106
+ .hljs-addition,
107
+ .hljs-stream,
108
+ .hljs-envvar,
109
+ .apache .hljs-tag,
110
+ .apache .hljs-cbracket,
111
+ .tex .hljs-command,
112
+ .hljs-prompt,
113
+ .hljs-name {
114
+ color: #8cbbad;
115
+ }
116
+
117
+ .hljs-string {
118
+ color: #ec7600;
119
+ }
120
+
121
+ .hljs-comment,
122
+ .hljs-annotation,
123
+ .hljs-blockquote,
124
+ .hljs-horizontal_rule,
125
+ .hljs-decorator,
126
+ .hljs-pi,
127
+ .hljs-deletion,
128
+ .hljs-shebang,
129
+ .apache .hljs-sqbracket,
130
+ .tex .hljs-formula {
131
+ color: #818e96;
132
+ }
133
+
134
+ .hljs-keyword,
135
+ .hljs-literal,
136
+ .css .hljs-id,
137
+ .hljs-doctag,
138
+ .hljs-title,
139
+ .hljs-header,
140
+ .hljs-type,
141
+ .vbscript .hljs-built_in,
142
+ .rsl .hljs-built_in,
143
+ .smalltalk .hljs-class,
144
+ .diff .hljs-header,
145
+ .hljs-chunk,
146
+ .hljs-winutils,
147
+ .bash .hljs-variable,
148
+ .apache .hljs-tag,
149
+ .tex .hljs-special,
150
+ .hljs-request,
151
+ .hljs-at_rule .hljs-keyword,
152
+ .hljs-status {
153
+ font-weight: normal;
154
+ }
155
+
156
+ .coffeescript .javascript,
157
+ .javascript .xml,
158
+ .tex .hljs-formula,
159
+ .xml .javascript,
160
+ .xml .vbscript,
161
+ .xml .css,
162
+ .xml .hljs-cdata {
163
+ opacity: 0.5;
164
+ }