Skip to content

Commit b84b0c2

Browse files
authored
v2.0.0: Remove file support, remove node 14 support, add TS type declaration (#8)
* Remove file support, node 14 support, add node 20 support * Update readme * Add ts type declaration, code style fixes * Improve readme, improve test * Improved code style, add boolean test
1 parent 2f8b346 commit b84b0c2

10 files changed

Lines changed: 1154 additions & 1754 deletions

File tree

.github/workflows/node.js.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616

1717
strategy:
1818
matrix:
19-
node-version: [14, 16, 18]
19+
node-version: [16, 18, 20]
2020
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
2121

2222
steps:

.github/workflows/npm-publish.yml

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,16 @@ on:
88
types: [created]
99

1010
jobs:
11-
build:
12-
runs-on: ubuntu-latest
13-
steps:
14-
- uses: actions/checkout@v3
15-
- uses: actions/setup-node@v3
16-
with:
17-
node-version: 18
18-
- run: npm ci
19-
- run: npm test
20-
2111
publish-npm:
22-
needs: build
2312
runs-on: ubuntu-latest
2413
steps:
2514
- uses: actions/checkout@v3
2615
- uses: actions/setup-node@v3
2716
with:
28-
node-version: 18
17+
node-version: 20
2918
registry-url: https://registry.npmjs.org/
3019
- run: npm ci
20+
- run: npm run build --if-present
3121
- run: npm publish
3222
env:
3323
NODE_AUTH_TOKEN: ${{secrets.npm_token}}

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ build/Release
4343
node_modules/
4444
jspm_packages/
4545

46-
# TypeScript v1 declaration files
46+
# TypeScript declaration files
4747
typings/
48+
index.d.ts
49+
index.d.ts.map
4850

4951
# Optional npm cache directory
5052
.npm

.npmignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.git
2+
.github
3+
.idea
4+
node_modules
5+
tsconfig.json

README.md

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
[![Node.js CI](https://github.com/bartvanraaij/php-array-reader/actions/workflows/node.js.yml/badge.svg)](https://github.com/bartvanraaij/php-array-reader/actions/workflows/node.js.yml)
44

5-
This small JS utility reads PHP files and strings containing arrays and returns a JavaScript object.
5+
This small JS utility reads PHP strings containing arrays and returns a JavaScript object.
66

77
It uses [glayzzle/php-parser](https://github.com/glayzzle/php-parser) to parse PHP into AST and uses that
88
info to extract arrays.
9-
It supports both indexed and associative arrays and array, string, numeric and null values.
9+
It supports both indexed and associative arrays (i.e. lists and dictionaries/maps) and array, string, numeric and null values.
1010

1111
## Installation
1212

@@ -18,57 +18,70 @@ npm install php-array-reader --save
1818

1919
## Usage
2020

21-
### With a PHP string
2221
```js
23-
const phpArrayReader = require('php-array-reader');
22+
import { fromString } from 'php-array-reader';
2423

2524
const phpString = `[
2625
'key' => 'string',
27-
'indexed_array' => [
26+
'list' => [
2827
'first',
2928
'second'
3029
],
31-
'associative_array' => [
30+
'dictionary' => [
3231
'foo' => 'bar',
3332
'hello' => 'world'
3433
],
3534
'also_supports' => null,
36-
'and_numeric' => 42
35+
'and_numeric' => 42,
36+
'what_about' => true,
37+
'or' => false,
3738
]`;
38-
const data = phpArrayReader.fromString(phpString);
39+
const data = fromString(phpString);
3940
```
4041
`data` will be this JS object:
4142
```js
4243
{
4344
key: 'string',
44-
indexed_array: ['first', 'second'],
45-
associative_array: {
45+
list: ['first', 'second'],
46+
dictionary: {
4647
foo: 'bar',
4748
hello: 'world'
4849
},
4950
also_supports: null,
50-
and_numeric: 42
51+
and_numeric: 42,
52+
what_about: true,
53+
or: false
5154
}
5255
```
5356

5457
### With a PHP file
58+
59+
Use [`fs.readFileSync`](https://nodejs.org/api/fs.html#fsreadfilesyncpath-options) or another file reading library to read the file, and pass
60+
that string into `fromString`, e.g.:
5561
```js
56-
const phpArrayReader = require('php-array-reader');
62+
import { fromString } from 'php-array-reader';
63+
import { readFileSync } from 'node:fs';
5764

5865
const phpFile = './file.php';
59-
const data = phpArrayReader.fromFile(phpFile);
66+
const phpString = readFileSync(phpFile);
67+
68+
const data = fromString(phpFile);
6069
```
6170

71+
> [!NOTE]
72+
> Version `1.x` of this library included a [`fromFile` method](https://github.com/bartvanraaij/php-array-reader/blob/a3f48acdef4eace2106ac40fa3c4593ab196dc1c/index.js#L6)
73+
> that allowed you to read a file directly. This has been removed in version `2.x` forward, because that method was a scope creep.
74+
6275
The PHP file can either return a single array, e.g.:
6376
```php
6477
<?php
6578
return [
6679
'key' => 'string',
67-
'indexed_array' => [
80+
'list' => [
6881
'first',
6982
'second'
7083
],
71-
'associative_array' => [
84+
'dictionary' => [
7285
'foo' => 'bar',
7386
'hello' => 'world'
7487
],
@@ -84,13 +97,13 @@ Or the PHP file may consist of multiple assigned arrays, e.g.:
8497
<?php
8598
$first = [
8699
'key' => 'string',
87-
'associative_array' => [
100+
'dictionary' => [
88101
'foo' => 'bar',
89102
'hello' => 'world'
90103
]
91104
];
92105
$second = [
93-
'index_array' => [
106+
'list' => [
94107
'first','second'
95108
],
96109
'also_supports' => null,
@@ -103,23 +116,15 @@ This will return a JS object with the variable names as the first level keys:
103116
{
104117
first: {
105118
key: 'string',
106-
associative_array: {
119+
dictionary: {
107120
foo: 'bar',
108121
hello: 'world'
109122
}
110123
},
111124
second: {
112-
index_array: ['first', 'second'],
125+
list: ['first', 'second'],
113126
also_supports: null,
114127
and_numeric: 42
115128
}
116129
}
117130
```
118-
You can then of course also use destructuring to assign the results to two variables:
119-
```js
120-
const phpArrayReader = require('php-array-reader');
121-
122-
const phpFile = './file.php';
123-
const { first, second } = phpArrayReader.fromFile(phpFile);
124-
```
125-

index.js

Lines changed: 85 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,97 @@
1-
const phpParser = require('php-parser'),
2-
fs = require('fs');
1+
'use strict';
32

4-
const readPhpArray = {
3+
const PhpParser = require('php-parser');
54

6-
fromFile: function(file) {
7-
const phpString = fs.readFileSync(file, 'utf8');
8-
return readPhpArray.fromString(phpString);
9-
},
5+
/**
6+
* Parse a string containing a PHP array into a JS object
7+
* @param {string} phpString - String containing a PHP array
8+
* @return {Object} The parsed object.
9+
*/
10+
function fromString (phpString) {
11+
const parser = new PhpParser({
12+
parser: {
13+
extractDoc: false,
14+
suppressErrors: true
15+
},
16+
ast: { withPositions: false }
17+
});
1018

11-
fromString: function(phpString){
12-
13-
const parser = new phpParser({
14-
parser: {
15-
extractDoc: false,
16-
suppressErrors: true
17-
},
18-
ast: { withPositions: false },
19-
});
20-
21-
phpString = phpString.trim();
22-
if(phpString.substr(0,5)!=='<?php') {
23-
phpString = '<?php \n'+phpString;
24-
}
25-
26-
const ast = parser.parseCode(phpString);
27-
28-
let phpObject = {};
29-
if (ast.kind === 'program') {
30-
31-
ast.children.forEach(child => {
19+
phpString = phpString.trim();
20+
if (phpString.substring(0, 5) !== '<?php') {
21+
phpString = '<?php \n' + phpString;
22+
}
3223

33-
if(child.kind==='expressionstatement' && child.expression.operator === '=' && child.expression.left.kind === 'variable' && child.expression.right.kind === 'array') {
34-
phpObject[child.expression.left.name] = readPhpArray.parseValue(child.expression.right);
35-
}
36-
else if(child.kind==='expressionstatement' && child.expression.kind === 'array'){
37-
phpObject = readPhpArray.parseValue(child.expression);
38-
}
39-
else if(child.kind === 'return' && child.expr.kind === 'array') {
40-
phpObject = readPhpArray.parseValue(child.expr);
41-
}
24+
const ast = parser.parseCode(phpString);
4225

43-
});
26+
let phpObject = {};
27+
if (ast.kind === 'program') {
28+
ast.children.forEach(child => {
29+
if (child.kind === 'expressionstatement' && child.expression.operator === '=' && child.expression.left.kind === 'variable' && child.expression.right.kind === 'array') {
30+
phpObject[child.expression.left.name] = parseValue(child.expression.right);
31+
} else if (child.kind === 'expressionstatement' && child.expression.kind === 'array') {
32+
phpObject = parseValue(child.expression);
33+
} else if (child.kind === 'return' && child.expr.kind === 'array') {
34+
phpObject = parseValue(child.expr);
35+
}
36+
});
37+
}
38+
return phpObject;
39+
}
4440

41+
/**
42+
* Parse a PHP expression to JavaScript
43+
* @private
44+
* @param {Object} expr The AST PHP expression.
45+
* @return {*} A JavaScript object or value.
46+
*/
47+
function parseValue (expr) {
48+
if (expr === null) return;
49+
if (expr.kind === 'array') {
50+
if (expr.items.length === 0) {
51+
return [];
4552
}
46-
return phpObject;
47-
},
48-
49-
/**
50-
* Parse a PHP expression to JavaScript
51-
* @param {Object} expr The AST PHP expression.
52-
* @return {*} A JavaScript object or value.
53-
*/
54-
parseValue: function(expr) {
55-
if(expr===null) return;
56-
switch(expr.kind) {
57-
case 'array':
58-
if (expr.items.length === 0) {
59-
return [];
60-
}
61-
const isKeyed = expr.items.every(item =>
62-
item === null || item.value === undefined || (item.key!==undefined && item.key !== null)
63-
);
64-
let items = expr.items.map(readPhpArray.parseValue).filter(itm => itm !== undefined);
65-
if (isKeyed) {
66-
items = items.reduce((acc, val) => Object.assign({}, acc, val), {})
67-
}
68-
return items;
69-
case 'entry':
70-
if (expr.key) {
71-
return {
72-
[readPhpArray.parseKey(expr.key)]: readPhpArray.parseValue(expr.value)
73-
}
74-
}
75-
return readPhpArray.parseValue(expr.value);
76-
case 'string':
77-
return expr.value;
78-
case 'number':
79-
return parseFloat(expr.value);
80-
case 'boolean':
81-
return expr.value;
82-
case 'nullkeyword':
83-
return null;
84-
break;
85-
case 'identifier':
86-
if(expr.name.name==='null') {
87-
return null;
88-
}
89-
break;
53+
const isKeyed = expr.items.every(item =>
54+
item === null || item.value === undefined || (item.key !== undefined && item.key !== null)
55+
);
56+
let items = expr.items.map(parseValue).filter(itm => itm !== undefined);
57+
if (isKeyed) {
58+
items = items.reduce((acc, val) => Object.assign({}, acc, val), {});
9059
}
91-
},
92-
93-
/**
94-
* Parse a PHP expression to JavaScript
95-
* @param {Object} expr The AST PHP expression.
96-
* @return {*} A JavaScript object or value.
97-
*/
98-
parseKey: function(expr) {
99-
switch(expr.kind) {
100-
case 'string':
101-
return expr.value;
102-
case 'number':
103-
return parseFloat(expr.value);
104-
case 'boolean':
105-
return expr.value ? 1 : 0;
106-
default:
107-
return null;
60+
return items;
61+
}
62+
if (expr.kind === 'entry') {
63+
if (expr.key) {
64+
return {
65+
[parseKey(expr.key)]: parseValue(expr.value)
66+
};
10867
}
68+
return parseValue(expr.value);
10969
}
70+
if (expr.kind === 'string') return expr.value;
71+
if (expr.kind === 'number') return parseFloat(expr.value);
72+
if (expr.kind === 'boolean') return expr.value;
73+
if (expr.kind === 'nullkeyword') return null;
74+
if (expr.kind === 'identifier' && expr.name.name === 'null') return null;
75+
return undefined;
76+
}
11077

111-
};
78+
/**
79+
* Parse a PHP expression to JavaScript
80+
* @private
81+
* @param {Object} expr The AST PHP expression.
82+
* @return {*} A JavaScript object or value.
83+
*/
84+
function parseKey (expr) {
85+
switch (expr.kind) {
86+
case 'string':
87+
return expr.value;
88+
case 'number':
89+
return parseFloat(expr.value);
90+
case 'boolean':
91+
return expr.value ? 1 : 0;
92+
default:
93+
return null;
94+
}
95+
}
11296

113-
module.exports = readPhpArray;
97+
module.exports = { fromString };

0 commit comments

Comments
 (0)