usercss-meta
v0.12.0
Published
Parse the metadata of usercss used by Stylus extension
Downloads
432
Readme
usercss-meta
Parse usercss metadata supported by the Stylus userstyle manager
Install
$ npm install --save usercss-meta
unpkg.com CDN:
- https://unpkg.com/usercss-meta/dist/usercss-meta.js
- https://unpkg.com/usercss-meta/dist/usercss-meta.min.js
This module depends on URL
parser. In Node.js, the module requires url
module. In the browser build, it uses global variable URL
.
Usage
const usercssMeta = require('usercss-meta');
const {metadata} = usercssMeta.parse(`/* ==UserStyle==
@name test
@namespace github.com/openstyles/stylus
@version 0.1.0
@description my userstyle
@author Me
@var text my-color "Select a color" #123456
==/UserStyle== */`);
/* => {
"vars": {
"my-color": {
"type": "text",
"label": "Select a color",
"name": "my-color",
"value": null,
"default": "#123456",
"options": null
}
},
"name": "test",
"namespace": "github.com/openstyles/stylus",
"version": "0.1.0",
"description": "my userstyle",
"author": "Me"
}
*/
usercssMeta.stringify(metadata, {alignKeys: true});
/* => `/* ==UserStyle==
@name test
@namespace github.com/openstyles/stylus
@version 0.1.0
@description my userstyle
@author Me
@var text my-color "Select a color" #123456
==/UserStyle== *\/`
*/
API Reference
This module exports following members:
- To parse metadata:
parse
: Function. Parse metadata and return an object.createParser
: Function. Create a metadata parser.ParseError
: Class.util
: Object. A collection of parser utilities.
- To stringify metadata:
stringify
: Function. Stringify metadata object and return the string.createStringifier
: Function. Create a metadata stringifier.
parse
const parseResult = parse(text: String, options?: Object);
This is a shortcut of
createParser(options).parse(text);
createParser
const parser = createParser({
unknownKey?: String,
mandatoryKeys?: Array<key: String>
parseKey?: Object,
parseVar?: Object,
validateKey?: Object,
validateVar?: Object,
allowErrors?: Boolean
});
unknownKey
decides how to parse unknown keys. Possible values are:
ignore
: The directive is ignored. Default.assign
: Assign the text value (characters before\s*\n
) to result object.throw
: Throw aParseError
.
mandatoryKeys
marks multiple keys as mandatory. If some keys are missing then throw a ParseError
. Default: ['name', 'namespace', 'version']
.
parseKey
is a key
/parseFunction
map. It allows users to extend the parser. Example:
const parser = createParser({
mandatoryKeys: [],
parseKey: {
myKey: util.parseNumber
}
});
const {metadata} = parser.parse(`
/* ==UserStyle==
@myKey 123456
==/UserStyle==
`);
assert.equal(metadata.myKey, 123456);
parseVar
is a variableType
/parseFunction
map. It extends the parser to parse additional variable types. For example:
const parser = createParser({
mandatoryKeys: [],
parseVar: {
myvar: util.parseNumber
}
});
const {metadata} = parser.parse(`/* ==UserStyle==
@var myvar var-name 'Customized variable' 123456
==/UserStyle== */`);
const va = metadata.vars['var-name'];
assert.equal(va.type, 'myvar');
assert.equal(va.label, 'Customized variable');
assert.equal(va.default, 123456);
validateKey
is a key
/validateFunction
map, which is used to validate the metadata value. The function accepts a state
object:
const parser = createParser({
validateKey: {
updateURL: state => {
if (/example\.com/.test(state.value)) {
throw new ParseError({
message: 'Example.com is not a good URL',
index: state.valueIndex
});
}
}
}
});
There are some builtin validators, which can be overwritten:
|Key|Description|
|---|-----------|
|version
|Ensure the value matches semver-regex then strip the leading v
or =
.|
|homepageURL
|Ensure it is a valid URL and the protocol must be http
or https
.|
|updateURL
|Same as above.|
|supportURL
|Same as above.|
validateVar
is a variableType
/validateFunction
map, which is used to validate variables. The function accepts a state
object:
const parser = createParser({
validateVar: {
color: state => {
if (state.value === 'red') {
throw new ParseError({
message: '`red` is not allowed',
index: state.valueIndex
});
}
}
}
});
Builtin validators:
|Variable Type|Description|
|-------------|-----------|
|checkbox
|Ensure the value is 0 or 1.|
|number
|Ensure sure the value is a number, doesn't exceed the minimum/maximum, and is a multiple of the step value.|
|range
|Same as above.|
If allowErrors
is true
, the parser will collect parsing errors while parser.parse()
and return them as parseResult.errors
. Otherwise, the first parsing error will be thrown.
parser.parse
const {
metadata: Object,
errors: Array
} = parser.parse(text: String);
Parse the text (metadata header) and return the result.
parser.validateVar
parser.validateVar(varObj);
Validate the value of the variable object. This function uses the validators defined in createParser
.
varObj
is the variable object in metadata.vars
:
const {metadata} = parse(text);
/* modify metadata.vars['some-var'].value ... */
for (const varObj of Object.values(metadata.vars)) {
validateVar(varObj);
}
ParseError
throw new ParseError(properties: Object);
Use this class to initiate a parse error.
properties
would be assigned to the error object. There are some special properties:
code
- error code.message
- error message.index
- the string index where the error occurs.args
- an array of values that is used to compose the error message. This allows other clients to generate i18n error message.
A table of errors thrown by the parser:
|err.code
|err.args
|Description|
|----------|----------|-----------|
|invalidCheckboxDefault
||Expect 0 or 1.|
|invalidRange
|Variable type|Expect a number or an array.|
|invalidRangeMultipleUnits
|Variable type|Two different units are defined.|
|invalidRangeTooManyValues
|Variable type|Too many values in the array.|
|invalidRangeValue
|Variable type|Values in the array must be number, string, or null.|
|invalidRangeDefault
|Variable type|The default value of @var range
must be a number. This error may be thrown when parsing number
or range
variables.|
|invalidRangeMin
|Variable type|The value is smaller than the minimum value.|
|invalidRangeMax
|Variable type|The value is larger than the maximum value.|
|invalidRangeStep
|Variable type|The value is not a multiple of the step value.|
|invalidRangeUnits
|[VARIABLE_TYPE, UNITS]
|The value is not a valid CSS unit.|
|invalidNumber
||Expect a number.|
|invalidSelect
||The value of @var select
must be an array or an object.|
|invalidSelectValue
||The value in the array/object must be a string.|
|invalidSelectEmptyOptions
||The options list of @var select
is empty.|
|invalidSelectLabel
||The label of the option is empty.|
|invalidSelectMultipleDefaults
||Multiple options are specified as the default value.|
|invalidSelectNameDuplicated
||Found duplicated option names.|
|invalidString
||Expect a string that is quoted with '
, "
, or `
.|
|invalidURLProtocol
|Protocol of the URL|Only http and https are allowed.|
|invalidVersion
|Version string|https://github.com/sindresorhus/semver-regex|
|invalidWord
||Expect a word.|
|missingChar
|A list of valid characters|Expect a specific character.|
|missingEOT
||Expect <<EOT ...
data.|
|missingMandatory
|A list of missing keys|This error doesn't have err.index
.|
|missingValue
||Expect a non-whitespace value.|
|unknownJSONLiteral
|Literal value|JSON has only 3 literals: true
, false
, and null
.|
|unknownMeta
|[META_KEY, SUGGESTED_META_KEY]
|Unknown @metadata
. It may suggest the correct metadata name if there is a typo. SUGGESTED_META_KEY
can be null|
|unknownVarType
|[META_KEY, VARIABLE_TYPE]
|Unknown variable type. META_KEY
could be var
or advanced
.|
util
A collection of parser utilities. Some of them might be useful when extending the parser.
eatWhitespace(state)
: Movestate.lastIndex
to next non-whitespace character.parseEOT(state)
: Parse EOT multiline string used by xStyle extension.parseJSON(state)
: Parse JSON value. Note that the JSON parser can parse some additional syntax like single quoted string, backtick quoted multiline string, etc.parseNumber(state)
: Parse numbers.parseString(state)
: Parse quoted string.parseStringToEnd(state)
: Parse the text value before line feed.parseWord(state)
: Parse a word. ([\w-]+
)
stringify
const text = stringify(metadata: Object, options?: Object);
This is a shortcut of:
createStringifier(options).stringify(metadata);
createStringifier
const stringifier = createStringifier(options?: Object);
options
may contain following properties:
alignKeys
: Boolean. Decide whether to align metadata keys. Default:false
.space
: Number|String. Same as thespace
parameter forJSON.stringify
.format
: String. Possible values are'stylus'
and'xstyle'
. This changes how variables are stringified (@var
v.s.@advanced
). Default:'stylus'
.stringifyKey
: Object. Extend the stringifier to handle specified keys.The object is a map of
key: stringifyFunction
pair.stringifyFunction
would receive one argument:value
: The value of the key, which is the same asmetadataObject[key]
.
The function should return a string or an array of strings.
stringifyVar
: Object. Extend the stringifier to handle custom variable type.The object is a map of
varType: stringifyFunction
pair. The function would receive three arguments:variable
: The variable which should be stringified, which is the same asmetadataObject.vars[variable.name]
.format
: Theformat
parameter of the option.space
: Thespace
parameter of the option.
The function should return a string which represents the default value of the variable.
Related
- Stylus userstyle manager - source of most of this code
- usercss metadata spec
- xStyle metadata spec - Also supported by this parser
License
MIT
Run tests
This repo includes 3 tests:
xo
linter - which could be invoked withxo
command.ava
test - which could be invoked withava
command.Browser test - we currently support Chrome 49+. To run the test:
- Run
npm run build
to build the browser dist. - Run
node browser-test
to generate browser test. - Open
browser-test.html
with a browser. - Open the console and ensure everything is OK.
- Run
Changelog
0.12.0 (Aug 1, 2021)
- Add: detect typo in
unknownMeta
error. - Change:
unknownMeta
error has two arguments now.
- Add: detect typo in
0.11.0 (Jul 6, 2021)
- Change: the version validator no longer follows semver strictly. Implement your own validator if you need strict version check.
0.10.1 (Jul 6, 2021)
- Fix: remove incompat features. Pass Chrome 49 browser test.
0.10.0 (Nov 19, 2020)
- Fix: precision issue when validating decimals.
- Change: allow hyphen in key name.
- Change: bump node version to 8.3.0.
0.9.0 (Nov 26, 2018)
- The repository is moved.
- Change:
parseStringToEnd
now throws an error if matched nothing. - Add:
missingValue
error.
0.8.4 (Nov 20, 2018)
- Add: support Chrome 49.
0.8.3 (Nov 7, 2018)
- Add:
invalidSelectLabel
/invalidSelectNameDuplicated
errors. - Add:
invalidSelect
/invalidSelectValue
errors. - Add: parse number exponent.
- Fix: version validator doesn't match the entire string.
- Fix: step validator doesn't match against min/max values.
- Add:
0.8.2 (Oct 3, 2018)
- Add:
invalidRangeUnits
error. - Fix: empty variable would make the parser consume the data after
\n
. - Fix: step validator is broken.
- Add:
0.8.1 (Sep 26, 2018)
- Add: attach variable type to range errors.
0.8.0 (Sep 23, 2018)
- Bump dependencies. Move
semver-regex
to package dependencies. - Change: while parsing
@advanced dropdown
, the result type would beselect
. - Add: the parser/stringifier for
@var number
and@var range
. - Add: parser method
parser.validateVar
. - Add: now
parseNumber
andparseJSON
accept decimals without leading zeros e.g..5
like CSS. - Add: asterisk syntax in
@var select
. - Add:
validateKey
andvalidateVar
arguments tocreateParser
. - Fix: when stringifying
@var select
in xstyle format, it should produce@advanced dropdown
instead of@advanced select
. - Fix: should throw an error with
@var dropdown
. - Fix: don't assign
advanced
key to metadata object.
- Bump dependencies. Move
0.7.1 (Sep 9, 2018)
- Breaking: the return value of
parser.parse
is changed. - Breaking: the signature of
ParseError
is changed. - Add:
createParser
now acceptsallowErrors
arg. - Change: some error messages are changed.
- Breaking: the return value of
0.6.1 (Jul 22, 2018)
- Fix:
stringify
would throw if the value is number instead of string.
- Fix:
0.6.0 (Jul 13, 2018)
- Change: the
url
module is shimmed withself.URL
by usingpkg.browser
. - Fix: stringify multi-line description.
- Change: the
0.5.0 (May 16, 2018)
- Change: the ParseResult object doesn't contain
vars
key if there is no variable in the input. - Fix:
var
key is accidentally assigned to ParseResult object.
- Change: the ParseResult object doesn't contain
0.4.0 (May 9, 2018)
- Rewrite the parser, cleanup unused stuff.
- Add stringify feature.