Upgrade to https://github.com/acornjs/acorn.git commit 84eda6bf
[jst.git] / src / options.js
1 import {hasOwn, isArray} from "./util.js"
2 import {SourceLocation} from "./locutil.js"
3
4 // A second argument must be given to configure the parser process.
5 // These options are recognized (only `ecmaVersion` is required):
6
7 export const defaultOptions = {
8   // `ecmaVersion` indicates the ECMAScript version to parse. Must be
9   // either 3, 5, 6 (or 2015), 7 (2016), 8 (2017), 9 (2018), 10
10   // (2019), 11 (2020), 12 (2021), 13 (2022), or `"latest"` (the
11   // latest version the library supports). This influences support
12   // for strict mode, the set of reserved words, and support for
13   // new syntax features.
14   ecmaVersion: null,
15   // `sourceType` indicates the mode the code should be parsed in.
16   // Can be either `"script"` or `"module"`. This influences global
17   // strict mode and parsing of `import` and `export` declarations.
18   sourceType: "script",
19   // `onInsertedSemicolon` can be a callback that will be called
20   // when a semicolon is automatically inserted. It will be passed
21   // the position of the comma as an offset, and if `locations` is
22   // enabled, it is given the location as a `{line, column}` object
23   // as second argument.
24   onInsertedSemicolon: null,
25   // `onTrailingComma` is similar to `onInsertedSemicolon`, but for
26   // trailing commas.
27   onTrailingComma: null,
28   // By default, reserved words are only enforced if ecmaVersion >= 5.
29   // Set `allowReserved` to a boolean value to explicitly turn this on
30   // an off. When this option has the value "never", reserved words
31   // and keywords can also not be used as property names.
32   allowReserved: null,
33   // When enabled, a return at the top level is not considered an
34   // error.
35   allowReturnOutsideFunction: false,
36   // When enabled, import/export statements are not constrained to
37   // appearing at the top of the program, and an import.meta expression
38   // in a script isn't considered an error.
39   allowImportExportEverywhere: false,
40   // By default, await identifiers are allowed to appear at the top-level scope only if ecmaVersion >= 2022.
41   // When enabled, await identifiers are allowed to appear at the top-level scope,
42   // but they are still not allowed in non-async functions.
43   allowAwaitOutsideFunction: null,
44   // When enabled, super identifiers are not constrained to
45   // appearing in methods and do not raise an error when they appear elsewhere.
46   allowSuperOutsideMethod: null,
47   // When enabled, hashbang directive in the beginning of file
48   // is allowed and treated as a line comment.
49   allowHashBang: false,
50   // When `locations` is on, `loc` properties holding objects with
51   // `start` and `end` properties in `{line, column}` form (with
52   // line being 1-based and column 0-based) will be attached to the
53   // nodes.
54   locations: false,
55   // A function can be passed as `onToken` option, which will
56   // cause Acorn to call that function with object in the same
57   // format as tokens returned from `tokenizer().getToken()`. Note
58   // that you are not allowed to call the parser from the
59   // callback—that will corrupt its internal state.
60   onToken: null,
61   // A function can be passed as `onComment` option, which will
62   // cause Acorn to call that function with `(block, text, start,
63   // end)` parameters whenever a comment is skipped. `block` is a
64   // boolean indicating whether this is a block (`/* */`) comment,
65   // `text` is the content of the comment, and `start` and `end` are
66   // character offsets that denote the start and end of the comment.
67   // When the `locations` option is on, two more parameters are
68   // passed, the full `{line, column}` locations of the start and
69   // end of the comments. Note that you are not allowed to call the
70   // parser from the callback—that will corrupt its internal state.
71   onComment: null,
72   // Nodes have their start and end characters offsets recorded in
73   // `start` and `end` properties (directly on the node, rather than
74   // the `loc` object, which holds line/column data. To also add a
75   // [semi-standardized][range] `range` property holding a `[start,
76   // end]` array with the same numbers, set the `ranges` option to
77   // `true`.
78   //
79   // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678
80   ranges: false,
81   // It is possible to parse multiple files into a single AST by
82   // passing the tree produced by parsing the first file as
83   // `program` option in subsequent parses. This will add the
84   // toplevel forms of the parsed file to the `Program` (top) node
85   // of an existing parse tree.
86   program: null,
87   // When `locations` is on, you can pass this to record the source
88   // file in every node's `loc` object.
89   sourceFile: null,
90   // This value, if given, is stored in every node, whether
91   // `locations` is on or off.
92   directSourceFile: null,
93   // When enabled, parenthesized expressions are represented by
94   // (non-standard) ParenthesizedExpression nodes
95   preserveParens: false
96 }
97
98 // Interpret and default an options object
99
100 let warnedAboutEcmaVersion = false
101
102 export function getOptions(opts) {
103   let options = {}
104
105   for (let opt in defaultOptions)
106     options[opt] = opts && hasOwn(opts, opt) ? opts[opt] : defaultOptions[opt]
107
108   if (options.ecmaVersion === "latest") {
109     options.ecmaVersion = 1e8
110   } else if (options.ecmaVersion == null) {
111     if (!warnedAboutEcmaVersion && typeof console === "object" && console.warn) {
112       warnedAboutEcmaVersion = true
113       console.warn("Since Acorn 8.0.0, options.ecmaVersion is required.\nDefaulting to 2020, but this will stop working in the future.")
114     }
115     options.ecmaVersion = 11
116   } else if (options.ecmaVersion >= 2015) {
117     options.ecmaVersion -= 2009
118   }
119
120   if (options.allowReserved == null)
121     options.allowReserved = options.ecmaVersion < 5
122
123   if (isArray(options.onToken)) {
124     let tokens = options.onToken
125     options.onToken = (token) => tokens.push(token)
126   }
127   if (isArray(options.onComment))
128     options.onComment = pushComment(options, options.onComment)
129
130   return options
131 }
132
133 function pushComment(options, array) {
134   return function(block, text, start, end, startLoc, endLoc) {
135     let comment = {
136       type: block ? "Block" : "Line",
137       value: text,
138       start: start,
139       end: end
140     }
141     if (options.locations)
142       comment.loc = new SourceLocation(this, startLoc, endLoc)
143     if (options.ranges)
144       comment.range = [start, end]
145     array.push(comment)
146   }
147 }